当我们用VS编译器按下Ctrl+F5编译代码后,编译器自动打印出代码的结果,在这个过程中,编译器经过预处理,编译,汇编和链接,最后才形成可执行文件(用二进制代码所写)。而VS已经更新很完善,不容易看出每步操作后的结果,所以我们需要借助Linux中的gcc编译器。
本文所需Linux的指令:ls:显示该目录下的所有文件; cd:进入目录(如:cd … 返回上级目录); touch:创建一个普通文件; mkdir:创建目录; rm:删除文件或目录。
然后还需要安装一个编辑器vim,安装链接:curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh。将链接直接复制到linux中,按回车自动配置。
首先创建一个目录:mkdir preproc;然后进入到该目录下:cd preproc; 在该目录下创建一个普通文件:touch test.c; 用vim打开进行编辑:vim test.c。编辑的代码如下:
#include <stdio.h>
#define M 20
#define PRINTF
int main()
{
printf("hello world!\n");
//printf("hello world!\n");
printf("%d\n",M);
printf("hello world!\n");
//printf("hello world!\n");
#ifdef PRINTF
printf("There have PRINTF!\n");
#else
printf("NONE PRINTF!\n");
#endif
return 0;
}
我们用gcc来编译上述c语言代码:gcc test.c;然后会得到a.out的可执行程序,./a.out就可以输出代码运行的结果。
预处理
预处理中编译器进行头文件展开、宏替换、去注释和条件编译等工作。
gcc -E test.c -o test.i:-E:从现在开始进行程序的翻译,预处理做完,就停下来。-o:将执行后的文件命名为test.i,test.i就是预处理后的文件。
然后打开vim test.i,会发现有800多行的代码,这是因为头文件的展开,编译器是不认识printf,想要printf正常运行,就必须引入头文件。预处理后的结果如下:
预处理后的语言还是c语言。
编译
编译是将c语言编译成汇编语言。
gcc -S test.c -o test.s:-S:从现在开始进行程序的翻译,当编译做完,就停下来。-o:将执行后的文件命名为test.s,test.s就是编译后的文件。
然后vim test.s,会看到如下汇编语言:对于字符串,编译器就直接记下,对于数字计算等,进行push,movl等操作。
汇编
汇编是将汇编语言转为可重定位目标二进制文件,但这个文件不可以被执行的,bin.obj。–只把我们自己的代码进行翻译形成二进制目标文件。
gcc -c test.c -o test.o:-c:从现在开始进行程序的翻译,当汇编做完,就停下来;-o:将执行后的文件命名为test.o,test.o就是汇编后的文件。
用vim打开后,就会看到如下乱码,这就是二进制目标文件。
最后一步就是链接。
链接
链接就是将我们这自己形成的.obj文件和库文件某种合并,形成可执行程序。
链接的时候可以链接静态库也可以链接动态库。
1.静态库和静态链接:链接的时候,如果是静态链接,找到静态库,拷贝静态库中的我所需要的代码到我自己的可执行程序中
2.动态库和动态链接:链接的时候,如果是动态链接,找到动态库,拷贝动态库中的我所需要的代码的地址到我自己的可执行程序中相关的位
3.静态链接成功:我们的程序,不依赖任何库,自己就可以独立运行
4.动态链接成功:我们的程序,还是依赖动态库,一旦动态库缺失,我们的程序便无法运行!
5.静态库,因为自身拷贝的问题,比较浪费空间
6.动态库:因为可以做到被大家共享方法,所以真正的实现永远都是在库中,程序内部只有地址,比较节省空间
7.静态库vs动态库:Linux默认使用的是动态链接和动态库!
安装静态库:yum install glibc-static libstdc+±static -y
连接静态库的话,加上-static即可。如:gcc test.c -o a.out-static -static
可以看到这大小差的不是一两点。
以上就是一个程序翻译的过程。