• Linux:gcc编译器


    gcc/g++

    • GCC:GNU Compiler Collection(GUN 编译器集合),它可以编译C、C++、JAV、Fortran、Pascal、Object-C等语言。
      • gcc是GCC中的GUN C Compiler(C 编译器)
        g++是GCC中的GUN C++ Compiler(C++编译器)
    • 由于编译器是可以更换的,所以gcc不仅仅可以编译C文件。所以,更准确的说法是:gcc调用了C compiler,而g++调用了C++ compiler

    gcc和g++的主要区别

    1. 对于 .c和.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的)

    2. 对于 .c和.cpp文件,g++则统一当做cpp文件编译

    3. 使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL

    4. gcc在编译C文件时,可使用的预定义宏是比较少的

    5. gcc在编译cpp文件时/g++在编译c文件和cpp文件时(这时候gcc和g++调用的都是cpp文件的编译器),会加入一些额外的宏。

    6. 在用gcc编译c++文件时,为了能够使用STL,需要加参数 –lstdc++ ,但这并不代表 gcc –lstdc++ 和 g++等价,它们的区别不仅仅是这个。


    gcc编译器

    • gcc可以分步骤编译,预处理,编译,汇编,最后链接生成可执行文件。
        可执行文件在Linux系统上一般表现位ELF目标文件(OBJ文件)。

    • 通过下列方式编译可以得到,每一步处理之后的过程文件:
      在这里插入图片描述

      • 也可以一步到位
      • 在这里插入图片描述
    • -static 此选项对生成的文件采用静态链接

    • -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统有动态库.

    • -O0-3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高

    • -w 不生成任何警告信息。

    • -Wall 生成所有警告信息。


    编译链接:

    • 预处理功能主要包括宏替换,文件包含,条件编译,去注释等。
    • 编译(生成汇编):在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
    • 汇编(生成机器可识别代码):汇编阶段是把编译阶段生成的“.s”文件转成“.o”的二进制目标文件
    • 链接:生成可执行文件或库文件
      在这里插入图片描述

    链接步骤:

    在这里插入图片描述

    1.符号解析
      程序中有定义和引用的符号(包括变量名,函数名),存放在符号表(.symtab)。符号表是一个结构数组,包含符号名、长度和位置等信息。编译器将符号的引用存放在重定位节(.rel.text和.rel.data)。链接器将每个符号的引用都与一个确定的符号定义建立关联。

    2.重定位
      将多个代码段和数据段分别合并为一个单独的代码段和数据段,计算每个定义的符号在虚拟地址空间的绝对地址。将可执行文件中的符号引用处修改为重定位后的地址信息。

    在这里插入图片描述


    file、ldd

    • 通过file 可执行文件ldd 可执行文件,可以看到文件的链接方式和动态链接库。
    • Linux操作系统下都是动态链接。
      在这里插入图片描述

    动态链接 vs 静态链接


    函数库:

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

    • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
    • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。
      • 动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,

    • 静态链接生成的文件虽然可以独立运行,但大小几乎是动态链接的10倍,体积过大。
    • 动态链接运行时需要再加载,省内存,编译效率高,但如果某个库缺失,程序就会挂掉。
      在这里插入图片描述

    参考文章


    • 为什么不直接把高级语言直接翻译成二进制呢?,,因为高级语言后出现,且再做一遍相关的转换工作,费时费力;所以先处理,在转成汇编就很方便。这是事情叫做站在前人的肩膀上;如果有什么bug,就叫做历史 遗留问题。

    • 编译器怎么直到我的代码是更新过的呢?
      修改文件的时候,会修改源文件时间窗,编译器会根据老的程序结合文件修改的时间进行对比,进而确定哪个文件被改过了,再编译特定的文件就可以了。
  • 相关阅读:
    什么?Coolbpf 不仅可以远程编译,还可以发现网络抖动!
    [Java安全]—再探Filter内存马
    基于SSM的教学管理系统设计与实现
    SQL Server教程 - SQL Server 压缩(Compression)
    基于正点原子stm32的mini板的TFTLCD显示实验
    剑指 Offer 62 圆圈中最后剩下的数字 Java
    《SQLi-Labs》04. Less 23~28a
    蚁群算法ACO求解连续函数问题
    【python】python内置函数 ——round()获取浮点数的四舍五入值
    硬件故障诊断:快速定位问题
  • 原文地址:https://blog.csdn.net/WTFamer/article/details/125939867