gcc使用总结

[复制链接]
查看893 | 回复6 | 2023-9-4 08:55:41 | 显示全部楼层 |阅读模式

安装gcc

(基于debian系Linux): 一次性把后面需要的都装了

sudo apt instal gcc g++ gdb

gcc和g++的区别

个人觉得最明显的区别就是:g++编译不论是.c文件还是.cpp文件,都当作cpp文件去编译,而gcc的做法是.c文件就当成c文件编译,.cpp文件就当成cpp文件编译。 所以一般编译的时候: .c文件:使用gcc编译 .cpp文件: 使用g++编译

gcc和g++配置不同的C标准

对于C89和C99存在差异的语法点,有时候需要使用不同的C标准进行编译!gcc/g++ -std=编译标准,

gcc -std=c89 main.c

image.png

gcc编译过程

从源代码生成可执行文件可以分为四个步骤,分别是预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)和链接(Linking)

预处理

预处理过程主要是处理那些源文件和头文件中以#开头的命令,比如 #include、#define、#ifdef 等。预处理的规则一般如下:

  • 将所有的#define删除,并展开所有的宏定义。
  • 处理所有条件编译命令,比如 #if、#ifdef、#elif、#else、#endif 等。
  • 处理#include命令,将被包含文件的内容插入到该命令所在的位置,这与复制粘贴的效果一样。注意,这个过程是递归进行的,也就是说被包含的文件可能还会包含其他的文件。
  • 删除所有的注释//和/ ... /。
  • 添加行号和文件名标识,便于在调试和出错时给出具体的代码位置。
  • 保留所有的#pragma命令,因为编译器需要使用它们。
gcc -E main.c    //默认不会改变文件内容,只是会通过中断打印出来预处理后的文件内容

// 可以使用-o选项将预处理的结果输出出来,一般用 .i 文件表示预处理结果文件
gcc -E main.c -o main.i

编译

编译就是把预处理完的文件进行一些列的词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。编译是整个程序构建的核心部分。

gcc -S main.c    //会生成一个 .s 文件

image.png 查看一下生成的汇编代码: image.png

汇编

汇编的过程就是将汇编代码转换成可以执行的机器指令,这个过程会生成一个.o文件,也叫做目标文件。

gcc -c main.c    // 会生成一个 .o 文件

image.png

链接

目标文件已经是二进制文件,与可执行文件的组织形式类似,只是有些函数和全局变量的地址还未找到,程序不能执行。链接的作用就是找到这些目标地址,将所有的目标文件组织成一个可以执行的二进制文件。

gcc main.c

默认生成的是a.out文件,可以直接执行!

手动添加链接库

如下程序中使用到math.h库,直接进行编译的时候提示找不到对应的链接库,此时就需要手动添加链接库:

#include <stdio.h>      /* printf */
#include <math.h>       /* cos */
#define PI 3.14159265
int main ()
{
    double param, result;
    param = 60.0;
    result = cos ( param * PI / 180.0 );
    printf ("The cosine of %f degrees is %f.\n", param, result );
    return 0;
}
gcc main.c -o main.out -lm

其中,-l选项表示手动添加链接库,m表示的是一个基本名,就是以m为检索词去检索链接库

链接其他目录的库

1 把链接库作为一般的目标文件,为 GCC 指定该链接库的完整路径与文件名。

gcc main.c -o main.out /usr/lib/libm.a

2 使用-L选项,为 GCC 增加另一个搜索链接库的目录:

gcc main.c -o main.out -L/usr/lib -lm

3 把包括所需链接库的目录加到环境变量 LIBRARYPATH 中。

动态/静态链接库

在C语言的头文件中可以看到很多声明的函数,但是实际上我们找不到其对应的具体实现,而这些函数的具体实现就是包含在链接库中。

静态链接库

静态链接库实现链接操作的方式很简单,即程序文件中哪里用到了库文件中的功能模块,GCC 编译器就会将该模板代码直接复制到程序文件的适当位置,最终生成可执行文件。 使用静态库文件实现程序的链接操作,既有优势也有劣势:

  • 优势是,生成的可执行文件不再需要任何静态库文件的支持就可以独立运行(可移植性强);
  • 劣势是,如果程序文件中多次调用库中的同一功能模块,则该模块代码势必就会被复制多次,生成的可执行文件中会包含多段完全相同的代码,造成代码的冗余。

gcc生成静态链接库

首先把需要生成动态链接库的源文件生成目标文件: gcc -c add.c sub.c 然后将生成的.o文件打包成链接库文件 ar rcs libmath.a add.o sub.o 这里需要注意的是静态链接库的命名:lib是静态链接库的前缀,所以是必须要有的。math这个才是我们打包的静态链接库的名字,然后静态链接库是以.a命名的

gcc使用静态链接库

首先把需要使用静态链接库的文件生成目标文件: gcc -c main.c 然后将生成的.o文件与静态链接库进行链接: gcc -static main.o libmath.a -o main.exe 生成的main.exe文件就可以直接执行了 image.png

动态链接库

动态链接库,又称为共享链接库。和静态链接库不同,采用动态链接库实现链接操作时,程序文件中哪里需要库文件的功能模块,GCC 编译器不会直接将该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件。 显然,这样生成的可执行文件是无法独立运行的。采用动态链接库生成的可执行文件运行时,GCC 编译器会将对应的动态链接库一同加载在内存中,由于可执行文件中事先记录了所需功能模块的位置信息,所以在现有动态链接库的支持下,也可以成功运行。 采用动态链接库实现程序的连接操作,其优势和劣势恰好和静态链接库相反:

  • 优势是,由于可执行文件中记录的是功能模块的地址,真正的实现代码会在程序运行时被载入内存,这意味着,即便功能模块被调用多次,使用的都是同一份实现代码(这也是将动态链接库称为共享链接库的原因)。
  • 劣势是,此方式生成的可执行文件无法独立运行,必须借助相应的库文件(可移植性差)。

gcc生成动态链接库

可以使用下面的命令直接生成动态链接库:

gcc -fpic -shared 源文件名... -o 动态链接库名

下面是应用实例: image.png

gcc使用动态链接库

直接借助动态链接库生成main的可执行文件:

gcc main.c libmath.so -o main.exe

然后发现main.exe无法直接执行,虽然动态链接库和main在项目目录下。Why? 这是因为运行时找不到这个动态链接库,因为运行的时候系统只会去找特定的几个目录,所以解决方案就是让系统也来找一下我们当前的目录,或者把这个动态链接库放到系统能找到的特定目录下去:

  • 将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64);
  • 在终端输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中 xxx 为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效);
回复

使用道具 举报

翁vjk | 2023-9-4 10:00:40 | 显示全部楼层
学习学习
回复

使用道具 举报

粉色小风扇 | 2023-9-4 10:15:05 | 显示全部楼层
向大佬学习
回复 支持 反对

使用道具 举报

ai_mcu | 2023-9-4 10:18:29 | 显示全部楼层
跟着大佬进步
明天总会更好
回复 支持 反对

使用道具 举报

爱笑 | 2023-9-4 10:34:19 | 显示全部楼层
打卡学习!
用心做好保姆工作
回复

使用道具 举报

jkernet | 2023-9-4 12:58:24 | 显示全部楼层
优质文章!学习了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则