目录
前言:
使用 gcc/g++:
代码的编译过程:
预处理:
头文件展开:
宏替换+去注释:
编辑
条件编译:
编译:
汇编:
链接:
动态库(动态链接):
静态库(静态链接):
前言:
我们写完一段源代码后,需要让代码跑起来,在Linux中,我们使用 gcc/g++来编译C语言/C++代码。
使用 gcc/g++:
我们现在新建了一个文件,且代码如下:
gcc [ 源代码文件名 ] 就可以对指定的代码文件进行编译,编译时会生成一个可执行程序,如果没有为可执行程序命名,默认文件名为 a.out,运行 a.out ,就会运行我们所写的代码!
我们也可以为可执行程序命名,gcc [ 源代码文件名 ] -o [ 可执行程序文件名 ]!
-o 后接目标文件。
g++ 的使用方法和 gcc 相同,这里不再赘述。
需要区别的是,gcc只能编译 C语言 ,g++可以编译 C语言 和 C++!
代码的编译过程:
预处理:
预处理时,会对代码进行宏替换、去掉注释、条件编译、头文件展开,如果想查看预处理后的代码,以 gcc 为例:gcc -E test.c -o test.i ,就可以把预处理后的代码存放到指定的文件中,注意,目标文件后缀为 .i 。
-E 表示从现在开始进行程序的预处理过程,当预处理工作结束后,就停下来,不再进行后续的工作!
头文件展开:
虽然我们原来的代码只有15行,经过头文件展开后,代码行数已经达到851行!
宏替换+去注释:
如果代码中有注释和宏定义,预处理时,会进行宏替换和删除注释,通过下面的对比可以看出:
条件编译:
由于宏定义时只定义了VERSION1,在条件编译时,只有VERSION1的代码保留下来,其余未定义的全部被动态裁剪了!若只定义了VERSION2,或者没有宏定义,也同理!
可以看出,预处理时,可以对代码进行编辑和裁剪。
我们也可以在预处理的指令中进行宏定义, 即使在源代码中我们没有定义 VERSION1,但我们在指令中定义了,效果和在源代码中定义相同!
指令: gcc -E test.c -o test.i -D VERSION1=1
条件编译可以防止头文件重复包含!头文件重复包含,会导致头文件展开时,代码量太大,导致编译效率低下!我们需要规避头文件重复包含!这是个好的编程习惯。
#ifndef _NAME_H
#define _NAME_H
//头文件内容
#endif
这里的 _NAME_H 可以是自定义的宏,这里的宏应为独一无二的,不可以与文件中的其他宏的名字相同!
# ifndef _NAME_H (if not define _NAME_H ):
1、如果宏_NAME_H未定义,那么就会走 #define _NAME_H 语句,定义宏 _NAME_H,并且引入头文件;
2、如果宏_NAME_H已经定义了,则不会走 #define _NAME_H 语句,直接进入#endif,不引入头文件 。
编译:
编译时,把代码转为汇编语言。
-S:从现在开始进行程序的编译,当编译工作完成,就停下来!
形成汇编文件,可以直接在预处理的文件上进行编译,也可以直接在源代码上进行编译,即两种写法:gcc -S test.c -o test.s (在源代码上)或 gcc -S test.i -o test.s(在预处理后的文件上)。
汇编:
汇编时,把编译后生成的汇编语言转为二进制语言!
-c :从现在开始进行程序的汇编,汇编工作结束后,就停下来!
同样可以在源代码的基础上进行汇编,也可以在编译文件上进行汇编!
转为二进制后,代码还不可以运行起来,即使开放了可执行权限,也是运行不起来的!
还需要最后一步--链接!
链接:
直接 gcc test.o -o test 就可以进行链接,所谓链接,就是把代码和库文件进行链接,默认与动态库进行链接。
ldd 可以查看代码和动态库还是静态库产生链接:
在 Linux 中,动态库以 .so 结尾,静态库以 .a 结尾;
在Windows中,动态库以 .dll 结尾,静态库以 .lib 结尾。
动态库(动态链接):
动态库在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入。
程序运行时,如果我们需要调用 printf 函数, printf 函数会被修改为库函数中 printf 实现的地址,这时候动态链接就建立好了。
动态库也叫共享库。
优点:比较节省资源(内存资源、网络资源等),不会出现太多的重复的代码;
缺点:对库的依赖性比较强,一旦库丢失,所有依赖该库的程序都无法运行。
用 file 命令查看文件类型时,可以看出代码是动态链接的:
静态库(静态链接):
编译链接时,把库文件的代码全部加入到可执行文件中。
优点:可执行程序不依赖库,同类型平台中进行跨平台使用;
缺点:生成的文件比较大,比较浪费资源(占用内存--内存资源、网络传输时传输量大--网络资源等)。
代码默认与动态库链接,我们也可以让代码与静态库链接:
gcc -o mybin-static test.c -static 就可以让代码与静态库链接,但是系统是默认没有安装静态库的,此时静态链接会出错,我们需要在系统中下载静态库!
在普通用户下,sudo yum install -y glibc-static libstdc++-static 就可以安装静态库。
安装完成后,用 ldd 和 file 命令可以看出,test-static 与静态库链接。
test 是动态链接的,test-static 是静态链接的,通过对比可以看出, 同样的源代码,静态链接的代码占用的空间比动态链接的大很多。
本文到这里就结束了,欢迎各位大佬的指正!