Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

你真的会写“Hello world!”吗?

$
0
0

标签(空格分隔): 程序人生


“Hello world!”是很多的程序员的第一个程序,不管是什么语言,“Hello world!”总被当作是程序员通向里另一个世界的大门,你真的知道一个“Hello world!”的程序是如何在计算机内部执行的吗?

1.编写一个“Hello world!”并执行

  • 新建一个hello.c
root@vmuser-virtual-machine:/home/vmuser# vim hello.c

2.开始写一个“Hello World”

#include<stdio.h>
void main()
{
 printf("Helllo World\n");
}

3.编译

root@vmuser-virtual-machine:/home/vmuser# gcc hello.c -o hello
//如果写的没有错误,那么将会在当前的目录下生成“hello”的可执行文件

4.执行

root@vmuser-virtual-machine:/home/vmuser# ./hello

如图所示
hello world 的运行结果
这样你的确是会写一个“Hello world!”了。然而并不是这样!

2.什么是程序?

“Hello world!”的生命周期是从一个源文件“hello.c”开始的,其实也就是一个文本文档,其实也就是一个由0和1组成的编码的集合。现代操作系统的大部门的文本文档采用的编码方式一般都为ASCII编码。看下图,我们看看一段“Hello world!”的程序的源码是如何在计算机内部表示的!
Hello World的ASCII编码
我们可以看到“hello world”在计算机内部的存贮方式,但是实际上只不过是一串的二进制的‘010101……’的编码序列这样给我们的启示是,程序其实就是计算机内部的一些信息,然而计算机语言的作用就是我们如何的编码和解码,从而实现一个特定的作用。

GCC的编译过程

编译 hello.c 命令很简单,但实际上,看似很简单的这一步操作,却隐藏了很多操作细 节。下面将通过这个示例,对其中的一些细节进行还原和了解。一个计算机程序,从编码到执行计算机内部要完成以下的几个过程:
- 预处理
预处理器(cpp)根据#开头的命令,修改原始的c程序,将#后面的内容代替为头文件本身的内容,并把它插入程序文本之中,结果就得到了另一个以hello.i为扩展名的c程序。

在这里GCC要加上参数 -E

root@vmuser-virtual-machine:/home/vmuser# gcc -E hello.c -o hello.i

此时会生成hello.i的程序
hello.i
用vi编辑器打来之后
此处输入图片的描述
一个简单的Hello world 居然有800多行的代码
跳转到末尾
此处输入图片的描述
可以看出,其实多余的代码就是有#include

root@vmuser-virtual-machine:/home/vmuser/he# gcc -S hello.i 

此处输入图片的描述
用vi打开hello.s文件,可以可以看到汇编代码
此处输入图片的描述
- 汇编
汇编器(as)的作用是将hello.s的汇编程序程序打包成可以重新定位的目标程序->hello.o,也可以叫做可执行文件
得到了汇编文件后,通过 gcc 就可以得到机器码了。在终端输入下列命令,可以得到 hello.o 文件。

root@vmuser-virtual-machine:/home/vmuser/he# gcc -c hello.s

此处输入图片的描述

那么此时万事大吉了吗?No!
- 链接
请注意,由于”hello word”程序用了printf函数,链接器(ld)的作用就是将printf.o的可rm执行文件已某种方式合并到hello文件中,这样才可以生成可执行的hello文件!
尽管已经得到了机器码,但还是不可以运行的,必须要经过链接才能运行。在终端输入 下列命令,将会得到可执行文件 a.out。

root@vmuser-virtual-machine:/home/vmuser/he# gcc hello.o

生成了a.out的可执行文件
此处输入图片的描述
a.out 是 gcc 默认输出文件名称,可以通过-o 参数指定新的文件名。例如加上“-o hello” 参数,将会生成 hello 文件,这个文件和 a.out 实际上是一样的,用 md5sum 命令计算文件校 验值,两者完全一样
此处输入图片的描述
链接可分为动态链接和静态链接:
动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态 库才能运行。动态链接生成的程序小巧,但是必须依赖动态库,否则无法执行。

  • Linux 下的动态链接库实际是共享目标文件(shared object), 一般是.so 文 件,作用类似于 Windows
    下的.dll 文件。  静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直 接运行,不过体积较大。

  • Linux 下静态库是汇编产生的.o 文件的集合,一般以.a 文件形式出现。 gcc 默认是动态链接,加上-static
    参数则采用静态链接。再来看 hello.c 示例,在链接的 时候加上-static 参数:

  vmuser@Linux-host:hello$ gcc hello.o -static -o hello_static

此处输入图片的描述

可以看到,动态链接生成的文件大小是 8379字节, 而静态链接生成的文件却有 879558 字节,体积明显大了很多。
总的过程可以用图来描述
此处输入图片的描述

此时生成的文件才可以执行了!

(持续更新)

作者:jianxinyou1990 发表于2016/10/21 13:36:14 原文链接
阅读:11 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>