> 文章列表 > Linux编译器 gcc与g++

Linux编译器 gcc与g++

Linux编译器 gcc与g++

Linux编译器 gcc/g++工具

目录

  • Linux编译器 gcc/g++工具
    • 1、程序的诞生
    • 2、gcc工具
      • 2.1 预处理
      • 2.2 编译
      • 2.3 汇编
      • 2.4 链接
      • 2.5 运行
      • 2.6 总结
    • 3、静态链接与动态链接
      • 3.1 静态链接
      • 3.2 动态链接
      • 3.3 Linux下库的命名

1、程序的诞生

程序的编译过程:

1、预处理(头文件包含、消除注释、宏定义替换)

2、编译(将语言替换成汇编代码)

3、汇编(将汇编指令转换为二进制指令)

4、链接(合并段表、符号表合并及重定位)

Linux编译器 gcc与g++

2、gcc工具

我们可以通过gcc工具实现程序的编译过程:

Linux编译器 gcc与g++

2.1 预处理

预处理会完成:①头文件包含,②define定义符号的替换和删除定义的符号,③删除注释

语法:

gcc [选项] [文件名] [选项] [生成文件名]

选项:

  • -E:该选项的作用是让gcc在预处理结束后停止编译过程;
  • -o:指明生成的目标文件

使用gcc进行预处理:

gcc -E Test.c -o Test.i

这里预处理程序Test.c,生成预处理后的文件并命名为Test.i;由于Linux文件类型与后缀无关,因此这里命名文件后缀名是为了方便用户明确其文件类型

Linux编译器 gcc与g++

2.2 编译

gcc首先要检查代码的规范性,是否有语法错误等,然后把C语言代码转换成汇编代码

语法:

gcc [选项] [文件名] [选项] [生成文件名]

选项:

  • -S:只进行编译而不进行汇编,生成汇编代码。
  • -o:指明生成的目标文件

使用gcc对已经预处理的文件进行汇编:

gcc -S Test.i -o Test.s

Linux编译器 gcc与g++

2.3 汇编

在汇编阶段会把汇编代码转换成二进制指令,同时会形成符号表

语法:

gcc [选项] [文件名] [选项] [生成文件名]

选项:

  • -c:汇编代码转化为.o的二进制目标代码
  • -o:指明生成的目标文件

使用gcc对已经完成编译的文件进行汇编:

gcc -c Test.s -o Test.o

Linux编译器 gcc与g++

我们使用vim编辑器查看Test.o文件:

vim Test.o

Linux编译器 gcc与g++

可以看到已经将汇编文件转化为二进制代码了,我们已经看不懂了

2.4 链接

链接的作用是将汇编完成后的二进制文件生成可执行文件

语法:

gcc [文件名] [选项] [生成文件名]

默认情况生成a.out,可以使用-o选项指明生成的目标文件:

gcc Test.o -o test 

Linux编译器 gcc与g++

也可以直接默认生成:

gcc Test.o

Linux编译器 gcc与g++

2.5 运行

当我们完成预处理—>编译—>汇编—>链接步骤后得到了我们的可执行文件,此时我们通过./来运行该可执行文件即可:

./a.out
./Test.exe

Linux编译器 gcc与g++

2.6 总结

以上我们通过gcc工具,通过四个步骤最终实现了程序的编译过程,最终得到可执行文件:

Linux编译器 gcc与g++

其中选项含义:

  • -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面;
  • -S 编译到汇编语言不进行汇编和链接;
  • -c 编译到目标代码;
  • -o 文件输出到文件;

👉 以上四个步骤我们可以通过gcc一步完成:

gcc hello.c                  #直接生成可执行文件

默认生成a.out可执行文件,也可通过-o选项重新命名:

gcc hello.c -o hello.exe     #将可执行文件命名为hello.exe

Linux编译器 gcc与g++

3、静态链接与动态链接

例如当我们使用printf函数时,是直接使用的库函数,库函数的代码在库文件中,因此库文件在何时,以怎样的方式加入到我们的程序当中的呢?下面我们将探讨这个问题。

3.1 静态链接

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

优势:不受库升级或者被删除的影响;
劣势:形成的可执行程序体积太大,浪费资源(可能在网络、磁盘、内存上占用了很大的资源)。

3.2 动态链接

动态链接与静态相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库文件。动态链接链接动态库,其后缀一般为.so。

优势:形成的可执行程序体积小,很好地节省资源(网络、磁盘、内存);
劣势:受库升级或者被删除的影响

例如我们以hello world程序为例:

gcc hello.c -o hello       #编译程序
file hello                 #查看该可执行程序

Linux编译器 gcc与g++

即:dynamically linked

可知Linux下使用的是动态链接!

ldd hello                  #查看动态链接库

Linux编译器 gcc与g++

3.3 Linux下库的命名

动态库:

libxxxxx.so 去掉前缀lib,去掉后缀.so,剩下的即是该库名

例如刚刚我们查看的静态链接库:

Linux编译器 gcc与g++

静态库:

libyyyyy.a 去掉前缀lib,去掉后缀.a,剩下的即是该库名

需要注意的是,Linux下静态链接需要使用静态库,而操作系统中可能没有对应的静态库,需要下载:

sudo yum install -y glibc-static         #下载C标准静态库
sudo yum install -y libstdc++-static     #下载C++标准静态库 
sudo yum install -y gcc-c++              #下载g++

由于Linux下链接步骤默认为动态链接,因此在下载完静态库后我们可以通过-static指令实现静态链接:

gcc hello.c -o hello_static -static

Linux编译器 gcc与g++

可以看到同一个程序通过动态链接和静态链接形成的可执行文件体积大小差别极大(100倍)!