不可不知的gcc编译


一、gcc的工作流程

  gcc编译器将c源文件到生成一个可执行程序,中间一共经历了四个步骤:
在这里插入图片描述

  四个步骤并不是gcc独立完成的,而是在内部调用了其他工具,从而完成了整个工作流程, 其中编译最耗时, 因为要逐行检查语法。
在这里插入图片描述

  • 下面以 test.c 为例介绍 gcc 的四个步骤:
    gcc -E test.c -o test.i
    gcc -S test.i -o test.s
    gcc -c test.s -o test.o
    gcc test.o -o test
    一步生成最终的可执行程序:
    gcc test.c -o test

二、gcc 常用参数

  • -v 查看gcc版本号, --version也可以
    在这里插入图片描述

  • -E 生成预处理文件

  • -S 生成汇编文件

  • -c 只编译, 生成.o文件, 通常称为目标文件

  • -I 指定头文件所在的路径

  • -L 指定库文件所在的路径

  • -l 指定库的名字

    扫描二维码关注公众号,回复: 14097538 查看本文章
  • -o 指定生成的目标文件的名字

  • -g 包含调试信息, 使用gdb调试需要添加-g参数

  • -On n=0∼3 编译优化,n越大优化得越多

三、gcc编译测试

  • 1、创建一个.c文件:vim hello.c
    在这里插入图片描述

  • 2、gcc -E hello.c -o hello.i -----通过预处理器使头文件展开,宏替换、注释去掉
    在这里插入图片描述

  • 3、gcc -S hello.i -o hello.s -----通过编译器使C文件变为汇编文件
    在这里插入图片描述

  • 4、gcc -c hello.s -o hello.o -----通过汇编器将汇编文件变为二进制文件
    在这里插入图片描述

  • 5、gcc hello.o -o hello -----通过链接器将函数中相应的代码组合到目标文件中
    在这里插入图片描述

  • 6、./hello -----执行
    在这里插入图片描述

总结

  通过学习了解gcc编译的过程,我们将一个程序运行到结束的完整过程进行简单的叙述:

1、预编译
  预编译主要处理的是带#号的预编译指令,通过预处理器将注释去掉,文件展开,宏替换:

① 删除所有的#define,展开所有宏定义。

② 删除所有注释,//和/* */。

③ 处理所有条件预处理指令,如"#if"、"#endif"、"#ifdef"、“elif”、"#else"

④ 处理#include预编译指令,将文件内容替换到它的位置,此过程递归进行。

⑤ 保留所有#pragma编译器指令,编译器需要用到它们,如:#pragma once是为了防止文件被重复引用。

⑥ 添加行号和文件标识,便于编译时产生调试用的行号信息,即当编译出错或警告时能显示行号。

2、编译

  将预编译得到的.i或.ii文件通过编译器ccl进行一系列词义分析、语义分析、语法分析、优化生成.s的汇编代码文件。

3、汇编

  将编译得到的汇编代码文件转变为机器可以执行的指令(机器码文件),经过汇编产生的目标文件,在windows下为.obj,在linux下为.o。此过程由汇编器as完成。

4、链接

&emspl 将不同的源文件产生的目标文件进行链接,生成一个可执行程序。

补充:
链接分为静态链接和动态链接:

静态链接:

  将函数和数据被编译进一个二进制文件,也就是将所有程序模块都链接成一个单独的可执行文件。

优点:运行速度快。

缺点:会造成空间浪费,因为每个可执行程序中对所有需要的目标文件都要一份副本,如果多个程序对同一个目标文件依赖,就会产生多个相同的副本。

动态链接:

  将程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序。

优点:共享库、更新方便。

缺点:运行时,性能不如静态链接,因为它每次执行都需要链接。


期待大家和我交流,留言或者私信,一起学习,一起进步!

猜你喜欢

转载自blog.csdn.net/CltCj/article/details/123603499