你了解Linux编译器gcc的使用吗?

目录

 

1. 背景知识

2.详解翻译的四个过程

2.1 预处理(预编译)

分段编译:预处理(预编译)

2.2 编译

分段编译:编译

2.3 汇编

分段编译:汇编

2.4 链接

翻译阶段:链接

3.内容补充

3.1 gcc的补充

 gcc选项

gcc选项记忆

gcc中多文件的操作

3.2 函数库的补充

函数库 

函数库一般分为静态库和动态库


1. 背景知识

❤️我们先通过两张图来简单解释一下整个运行的过程!

你了解Linux编译器gcc的使用吗?_第1张图片

你了解Linux编译器gcc的使用吗?_第2张图片

❤️从上图我们可以看出整个翻译又分为四个过程:预处理(预编译)、编译、汇编、链接

2.详解翻译的四个过程

2.1 预处理(预编译)

补充:直接编译

❤️比如:我们写了一个在test.c文件,里面写入代码:

你了解Linux编译器gcc的使用吗?_第3张图片

 ❤️直接编译,默认生成a.out可执行文件;也可以加上-o参数,自己命名生成的可执行程序的名字

你了解Linux编译器gcc的使用吗?_第4张图片

你了解Linux编译器gcc的使用吗?_第5张图片

❤️无论是a.out 还是mytest直接./a.out或者./mytest都是可以直接就运行的!

分段编译:预处理(预编译)

❤️在预处理阶段主要包括:a.头文件的展开、b.去注释、c.宏替换、d.条件编译;

    ⭐️我们主要使用-E参数

    ⭐️gcc -E test.c -o test.i  第一步走完,停下!临时内容写入.i文件

❤️这里我们也有两种方法进行预编译

   ⭐️(1)我们再利用-o参数命名tes.i,把结果放到test.i文件里

你了解Linux编译器gcc的使用吗?_第6张图片

    ⭐️(2)利用>重定向到test.i文件中

 ❤️预处理过后结果还是C语言;我们不妨打开test.i进行查看

你了解Linux编译器gcc的使用吗?_第7张图片

2.2 编译

分段编译:编译

❤️在编译阶段主要是把C语言变成汇编语言;

❤️对于编译我们需要用到-S参数我们利用第一步的结果test.i继续往后编译;它会默认生成test.s文件:

 ❤️当然我们也可以再用-o选项,进行自己命名:gcc -S test.i -o test.s;也是可以的;

     ⭐️gcc -S test.i -o test.s  第二步走完,停下!临时内容写入.s文件

2.3 汇编

分段编译:汇编

❤️在汇编阶段主要是把汇编语言转换成机器指令(.o目标二进制文件,二进制不可执行);

 ❤️对于汇编我们需要用到-c参数我们利用第二步的结果test.s继续往后汇编;它会默认生成test.o文件:

你了解Linux编译器gcc的使用吗?_第8张图片

❤️当然我们也可以再用-o选项,进行自己命名:gcc -c test.s -o test.o;也是可以的;

     ⭐️gcc -c test.s -o test.o  第三步走完,停下!临时内容写入.o文件;

     ⭐️这个二进制文件我们看不懂,所以需要一个工具readelf;readelf -s test.o就可以正常阅读;也可以用od命令,以八进制形式打开;

2.4 链接

翻译阶段:链接

❤️链接阶段本质上引入我们在代码中常用的第三方库(C库);

❤️对于链接我们不需要参数,直接利用第三步生成的test.o二进制文件;去链接C库,最终生成可执行文件,默认是a.out;也可以用-o自己命名;

你了解Linux编译器gcc的使用吗?_第9张图片

 ❤️gcc会根据文件,进行默认链接(由编译器和文件共同决定);

❤️怎么验证链接的就是C库?我们可以用ldd命令去查看a.out所依赖的库

你了解Linux编译器gcc的使用吗?_第10张图片

⭐️静态库和动态库:libc-2.17.so以.so结尾叫动态库;libc.a以.a结尾叫静态库 ;

⭐️库的真正名字:是去掉lib,去掉第一个点(.),.XXX以后的的内容;剩下的就是库名字;

⭐️所以对于libc.so.6这个动态库,真正的名字就是C库(libc.so.6);验证链接的就是C库!

3.内容补充

❤️这里我们在补充一下gcc编译器的其它参数和函数库的一些知识点!便于我们的理解!

3.1 gcc的补充

 gcc选项

⭐️-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面;
⭐️-S  编译到汇编语言不进行汇编和链接;
⭐️-c  编译到目标代码;
⭐️-o 文件输出到 文件;
⭐️-static 此选项对生成的文件采用静态链接;默认生成的是链接,想要生成静态链接,就多加一个参数 -static就可以了;
⭐️-g 生成调试信息。GNU 调试器可利用该信息;
⭐️-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库;
⭐️-O0、-O1、-O2、-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,

-O3优化级别最高;
⭐️-w  不生成任何警告信息。
⭐️-Wall 生成所有警告信息。

gcc选项记忆

❤️对于我们常用的无非就时编译阶段的参数-E、-S、-c;与对应生成的.i、.s、.o文件!

⭐️对于编译时参数-E、-S、-c;我们就想到vim编译器里,按Esc可以回退到命令模式;这里的Esc不就刚好对应着-E、-S、-c?只需要注意的是,前两大写,最后一个小写;

⭐️对于生成的文件.i、.s、.o;我们就对比下载Centos镜像时,后缀是不是就是.iso?

gcc中多文件的操作

❤️这一次我们的.c文件只有一个;那如果像在VS中写成项目的模式,最终有多个.c文件,怎么链接成一个可执行文件呢?

    ⭐️(1)比如有3个.c文件:test.c、test1.c、test2.c我们链接成一个可执行文件;首先要先生成.o目标文件;gcc -c test.c、gcc -c test1.c、gcc -c test2.c会默认生成test.o、test1.o、test2.o文件;

    ⭐️(2)怎么把test.o、test1.o、test2.o链接起来生成一个可执行文件呢?

                  直接执行:gcc test.o test1.o test2.o -o a.out;

❤️总结:对于多文件情况,最好是将多文件统一编译成.o文件,然后把所有的.o文件链接生成可执行文件!当然直接把.c文件直接链接也是可以的!

   ⭐️当.c文件有几千的的时候,我们非要把所有的文件生成.o文件吗?当然不是,这就需要make和makefile,后面会讲解;

3.2 函数库的补充

函数库 

❤️我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
❤️解释:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用

函数库一般分为静态库和动态库

❤️静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”;

❤️动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库;
❤️gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示:gcc hello.o -o hello
❤️gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。

你可能感兴趣的:(Linux,linux,运维)