0


Linux编译器-gcc/g++使用

✅<1>主页:我的代码爱吃辣
📃<2>知识讲解:Linux
🔥<3>创作者:我的代码爱吃辣
💬<4>前言:上期我们学习了vim写代码,今天了解gcc执行代码,和动静态库。

一.gcc介绍

gcc是一个C语言编译器,和我们平时用的VS2022不是一个概念,VS2022不仅可以编辑代码还可以编译执行代码。他是整合了很多功能的集成开发环境,简称IDE。gcc只负责编译C语言代码。

gcc 使用:

gcc [选项] 要编译的文件 [选项] [目标文件]

二.gcc翻译过程

(1)预处理(进行宏替换)

指令:

gcc -E test.c -o test.i

说明:

  • 预处理功能主要包括宏定义,文件包含,条件编译,去注释等
  • -E选项:让代码进行预处理,预处理之后就停下来。
  • -o选项:后面紧跟着的是生成的目标文件名称,上面的命令也可以写成:gcc -o test.i -E test.c

** 举例:**

  1 #include<stdio.h>

  2 #define M 100
  3 #define MAX 10000

  4 int main()
  5 {
  6   printf("hello gcc%d\n",M);
  7   printf("hello gcc%d\n",M);
  8   printf("hello gcc%d\n",M);
  9   printf("hello gcc%d\n",MAX);
 10   printf("hello gcc%d\n",MAX);
 11   printf("hello gcc%d\n",MAX);                                                                                                                                                          
 12 
 13   return 0;
 14 }
 15 

我们发现,原本只有是几行的代码现在有了大还几百行。这就是因为在预处理阶段进行了头文件的展开,并且定义的宏也被替换了。

(2) 编译(生成汇编)

指令:

gcc -S test.i -o test.s

说明:

  • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
  • “-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

** 举例:**

查看test.s文件:

(3)汇编(生成机器可识别代码)

指令:

gcc -c test.s -o test.o

说明:

  • 汇编阶段是把编译阶段生成的“.s”文件转成目标文件
  • 选项“-c”:代码翻译到汇编结束就停下来,就可看到汇编代码已转化为“.o”的二进制目标代码了

** 二进制文件test.o:**

这既是二进制文件,我们当然是什么都看不懂了,这就是给计算机识别的文件。

那既然是二进制文件,可不可以执行呢?

告诉我们权限不够。

我们给他给予上执行权限:

告诉我们,test.o是无法执行的二进制文件,也就是说汇编生成的二进制文件是无法执行的。

(4)连接(生成可执行文件或库文件)

指令:

gcc test.o -o test

** 说明:**

  • 命令没有选项。
  • 直接生成可执行的文件。

执行:

(5)总结gcc

我们在使用gcc 不必 预处理,编译,汇编 ,链接,一步一步的执行,我们可以直接使用

gcc C语言源文件 -o 目标文件

gcc选项

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

三.动静态链接库

(1)函数库

我们在上卖面写的代码里面使用了printf函数,但是我们并没有定义printf函数,而且stdio.h头文件里面也只有printf函数的声明而已。那是哪里实现的printf函数呢?

系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到
系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函
数“printf”了,而这也就是链接的作用。

也就是说没有库, gcc 就无法对代码进行翻译。

其实我们从人生中写的第一个代码输出"hello word",就一直在使用库,也就是语言库。

例如上面的写的C语言代码,翻译形成的可执行文件 test ,它也依赖了库。

我们可以使用命令 :ldd,来查看文件依赖那些库。

ldd 【文件】

我们甚至可以看一下命令依赖哪些库:

** 这里不能发现 ls 命令也是依赖库的, 甚至依赖着C语言库,因为我们的命令有相当一部分就是C语言写的,其实命令也就是程序。**

(2) 动态库与静态库

函数库一般分为静态库和动态库两种:

  1. 静态库:格式为 lib***.a
  2. 动态库:格式为 lib***.so

libc.so.6就是一个动态库,lib是前缀,so是后缀,c就是库名字,6是版本号,libc.so.就是C语言的库。

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

** (3)动态链接与静态链接**

库的连接方式分为:动态链接和静态链接。

Linux下gcc默认是动态链接:

我们通过,file命令来查看可执行文件的连接方式。

file 【文件名】

我们将 file test 的内容输出重定向到 file.txt 中

那为什么linux下gcc 不去使用静态链接呢?我们先了解一下动态链接和静态链接。

  • 静态链接:连接的时候静态链接找到静态库,把库文件的代码全部加入到可执行文件中。
  • 优点:静态链接成功,程序将不依赖任何库,自己就可以独立运行。
  • 缺点:因为自身的拷贝的原因,比较房费空间。
  • 动态链接:链接时动态链接找到动态库,拷贝动态库中代码的地址到可执行程序中的相关位置。
  • 优点:因为可以做到被大家共享方法,所以真正的实现永远都是在库中,程序内部只有地址,比较节省空间。
  • 缺点:我们的程序还是依赖动态库,一旦动态库失效,程序就无法运行。

而Linux下使用动态库的原因就是,一般对应的动态库并不会出问题,还可以减小空间的消耗,综合考虑动态库更优。

(4)静态链接的使用

我们使用gcc 就可以实现默认动态链接,如果我们就是想使用静态链接呢?静态链接需要特定的方式来实现,而且linux默认只安装了动态库,要想实现静态链接还得先安装静态库。

安装静态库:

sudo yum install -y glibc-static

安装以后使用命令:

gcc test.c -o test_static -static

我们将file test.static 内容输出重定向到 file.txt 中。

** test_static 就是静态链接生成的可执行文件,并且我们发现,静态链接生成的可执行程序的大小,远大于动态链接生成的可执行程序的大小。**

标签: linux

本文转载自: https://blog.csdn.net/qq_63943454/article/details/128794060
版权归原作者 我的代码爱吃辣 所有, 如有侵权,请联系我们删除。

“Linux编译器-gcc/g++使用”的评论:

还没有评论