GCC编译过程

目录

GCC编译

方式一:一步完成

方式二:分步编译

 一、预处理

 二、编译

三、汇编(生成目标文件)

四、链接

gcc安装查看

方式一:

方式二:

快速安装gcc编译器

gcc 和 g++ 的区别

Linux执行文件


GCC编译

方式一:一步完成

打开命令行窗口(Terminal),编写如下 gcc 指令:

gcc hello.c

按下 Enter 回车键,由此 GCC 编译器就帮我们在当前目录下生成了对应的可执行文件,该文件的名称为 a.out,可以通过 ls 指令查看该文件是否存在:

[wlh@localhost ~]$ ls
a.out    demo.c

 在此基础上,我们可以执行该文件,查看其执行结果,继续编写如下指令:

[wlh@localhost ~]$ ./a.out
hello world

//存储在 hello.c 文件中
#include <stdio.h>
int main(){
   puts("hello world\n");
   return 0;
}

 注意:linux的可执行文件后缀名小知识:linux的可执行文件一般没有后缀,linux一般可以自动识别文件类型,有很多类型都不用加后缀。只要设了执行权限,有elf文件头,就可以看成可执行文件,有些时候可执行文件的后缀名为.out。Linux下的后缀名并没用windows下那么有用,Linux不根据扩展名判断文件类型,而是根据文件的内容来判断。所以扩展名的作用是帮助人来识别文件,对于Linux系统本身来说没有什么用处。

方式二:分步编译

所谓“分步编译”,即由用户手动调用 GCC 编译器完成对 C、C++源代码的预处理、编译、汇编以及链接过程,每个阶段都会生成对源代码加工后的文件。

表 1 GCC常用的编译选项
gcc/g++指令选项功 能
-E(大写)预处理指定的源文件,不进行编译。
-S(大写)编译指定的源文件,但是不进行汇编。
-c编译、汇编指定的源文件,但是不进行链接。
-o指定生成文件的文件名。

 一、预处理

通过为 gcc 指令添加 -E 选项,即可控制 GCC 编译器仅对源代码做预处理操作。

所谓预处理操作,主要是处理那些源文件和头文件中以 # 开头的命令(比如 #include、#define、#ifdef 等),将包含的“.h”文件插入对应位置,并删除程序中所有的注释 // 和 /* ... */,添加行号以及文件名标识,处理条件编译指令,展开所有的宏定义。

注,默认情况下 gcc -E 指令只会将预处理操作的结果输出到屏幕上,并不会自动保存到某个文件。因此该指令往往会和 -o 选项连用,将结果导入到指令的文件中。比如:

[wlh@localhost wlh01]$ gcc -E hello.c -o hello.i
[wlh@localhost wlh01]$ ls
hello.c  hello.i

 linux 系统中通常用 ".i" 作为 C 语言程序预处理后所得文件的后缀名。

可以通过执行cat helloo.i指令查看该文件中的内容,但通常没有足够 C 语言功底的读者是看不懂的。为此,我们可以为 gcc 指令再添加一个 -C 选项,阻止 GCC 删除源文件和头文件中的注释:

 二、编译

编译是整个程序构建的核心部分,也是最复杂的部分之一。所谓编译,简单理解就是将预处理得到的程序代码,经过一系列的词法分析、语法分析、语义分析以及优化,加工为当前机器支持的汇编代码。

通过给 gcc 指令添加 -S(注意是大写)选项,即可令 GCC 编译器仅将指定文件加工至编译阶段,并生成对应的汇编代码文件。例如:

[wlh@localhost wlh01]$ gcc -S hello.i
[wlh@localhost wlh01]$ ls
hello.c  hello.i  hello.s

 经过执行 gcc -S 指令,其生成了一个名为 hello.s 的文件,这就是经过编译的汇编代码文件。也就是说默认情况下,编译操作会自行新建一个文件名和指定文件相同、后缀名为 .s 的文件,并将编译的结果保存在该文件中。

当然如果需要的话,我们还可以为 gcc -S 指令添加 -o 选项,令 GCC 编译器将编译结果保存在我们指定的文件中。

[wlh@localhost wlh01]$ gcc -S hello.i -o test.s
[wlh@localhost wlh01]$ ls
hello.c  hello.i  hello.s  test.s

注:gcc -S 指令操作的文件并非必须是经过预处理后得到的 .i 文件,-S 选项的功能是令 GCC 编译器将指定文件处理至编译阶段结束。这也就意味着,gcc -S 指令可以操作预处理后的 .i 文件,也可以操作源代码文件:

  • 如果操作对象为 .i 文件,则 GCC 编译器只需编译此文件;
  • 如果操作对象为 .c 或者 .cpp 源代码文件,则 GCC 编译器会对其进行预处理和编译这 2 步操作。

三、汇编(生成目标文件)

汇编其实就是将汇编代码转换成可以执行的机器指令。大部分汇编语句对应一条机器指令,有的汇编语句对应多条机器指令。相对于编译操作,汇编过程会简单很多,它并没有复杂的语法,也没有语义,也不需要做指令优化,只需要根据汇编语句和机器指令的对照表一一翻译即可。

通过为 gcc 指令添加 -c 选项(注意是小写字母 c),即可让 GCC 编译器将指定文件加工至汇编阶段,并生成相应的目标文件。例如:

[wlh@localhost wlh01]$ ls
hello.c  hello.i  hello.s
[wlh@localhost wlh01]$ gcc -c hello.s
[wlh@localhost wlh01]$ ls
hello.c  hello.i  hello.o  hello.s
[wlh@localhost wlh01]$

可以看到,该指令生成了和 demo.s 同名但后缀名为 .o 的文件,这就是经过汇编操作得到的目标文件。

当然如果必要的话,还可以为 gcc -c 指令在添加一个 -o 选项,用于将汇编操作的结果输入到指定文件中,例如:

[wlh@localhost wlh01]$ ls
hello.c  hello.i  hello.o  hello.s
[wlh@localhost wlh01]$ ^C
[wlh@localhost wlh01]$ gcc -c hello.s -o test.o
[wlh@localhost wlh01]$ ls
hello.c  hello.i  hello.o  hello.s  test.o

 需要强调的一点是,和 gcc -S 类似,gcc -c 选项并非只能用于加工 .s 文件。事实上,-c 选项只是令 GCC 编译器将指定文件加工至汇编阶段,但不执行链接操作。这也就意味着:

  • 如果指定文件为源程序文件(例如 demo.c),则 gcc -c 指令会对 demo.c 文件执行预处理、编译以及汇编这 3 步操作;
  • 如果指定文件为刚刚经过预处理后的文件(例如 demo.i),则 gcc -c 指令对 demo.i 文件执行编译和汇编这 2 步操作;
  • 如果指定文件为刚刚经过编译后的文件(例如 demo.s),则 gcc -c 指令只对 demo.s 文件执行汇编这 1 步操作。

注:注意,如果指定文件已经经过汇编,或者 GCC 编译器无法识别,则 gcc -c 指令不做任何操作。

这里以 demo.c、demo.i、demo.s 为例,演示 gcc -c 指令的作用:

[root@bogon demo]# ls
demo.c  demo.i  demo.s
[root@bogon demo]# gcc -c demo.c -o democ.o
[root@bogon demo]# ls
demo.c  demo.i  democ.o  demo.s
[root@bogon demo]# gcc -c demo.i -o demoi.o
[root@bogon demo]# ls
demo.c  demo.i  demoi.o  democ.o  demo.s
[root@bogon demo]# gcc -c demo.s -o demos.o
[root@bogon demo]# ls
demo.c  demo.i  demoi.o  democ.o  demo.s  demos.o

 以上操作分别生成的 democ.o、demoi.o 以及 demos.o,其包含的二进制内容是完全一样的,只是文件名不同而已。

四、链接

链接器把多个二进制的目标文件(object file)链接成一个单独的可执行文件。在链接过程中,它必须把符号(变量名、函数名等一些列标识符)用对应的数据的内存地址(变量地址、函数地址等)替代,以完成程序中多个模块的外部引用。(静态链接和动态链接)

通过编译器的前3个步骤后,我们获得目标代码,但是里面的各个地址还没有确定,空间还没有分配。链接过程主要包括:地址和空间的分配,符号决议和重定位。

得到生成目标文件之后,接下来就可以直接使用 gcc 指令继续执行链接操作,例如:

[wlh@localhost wlh01]$ gcc hello.o -o hello.exe
[wlh@localhost wlh01]$ ls
hello.c  hello.exe  hello.i  hello.o  hello.s  test.o
[wlh@localhost wlh01]$ ./hello.exe
hello world

 gcc 会根据所给文件内容,自行判断出此类文件为目标文件,仅需要进行链接操作。(注意后缀名.o只是方便用户标识文件,并不影响linux判断该文件类型)如下所示:

[wlh@localhost wlh01]$ gcc -c hello.s -o test
[wlh@localhost wlh01]$ gcc test -o test.ext
[wlh@localhost wlh01]$ ./test.ext
hello world

gcc安装查看

方式一:

gcc --version

方式二:

rpm -qa gcc

快速安装gcc编译器

每个 Linux 发行版都有自己的软件包管理工具,比如 CentOS 系统的 yum 包管理器、Ubuntu 系统的 apt 包管理器等等,并且大多数 Linux 发行版都提供有 GCC 编译器的二进制软件包。因此,我们可以直接“傻瓜式”地安装 GCC 编译器(以 yum 为例):

yum -y install gcc
yum -y install gcc-c++

过执行这 2 条指令,就可以在 CentOS 系统中利用 gcc 命令来执行 C 语言程序,利用 g++ 命令来执行 C++ 程序。采用此方式安装的 GCC 编译器,版本通常较低。

gcc 和 g++ 的区别

只要是 GCC 支持编译的程序代码,都可以使用 gcc 命令完成编译。可以这样理解,gcc 是 GCC 编译器的通用编译指令,因为根据程序文件的后缀名,gcc 指令可以自行判断出当前程序所用编程语言的类别,比如:

  • xxx.c:默认以编译 C 语言程序的方式编译此文件;
  • xxx.cpp:默认以编译 C++ 程序的方式编译此文件。
  • xxx.m:默认以编译 Objective-C 程序的方式编译此文件;
  • xxx.go:默认以编译 Go 语言程序的方式编译此文件;、

但如果使用 g++ 指令,则无论目标文件的后缀名是什么,该指令都一律按照编译 C++ 代码的方式编译该文件。也就是说,对于 .c 文件来说,gcc 指令以 C 语言代码对待,而 g++ 指令会以 C++ 代码对待。但对于 .cpp 文件来说,gcc 和 g++ 都会以 C++ 代码的方式编译。

Linux执行文件

1、Linux下执行一个可执行的文件,不需要命令,直接写文件路径,会自动执行

linux下 .是当前目录,..是父目录, ./ 表示当前目录的全路径.

①如果想运行当前路径下的某个可执行文件且当前路径不在系统环境变量path中,就要这样运行:

./a.out

当然也可以写成绝对路径:

/home/tester/a.out

当然,前提条件是该文件是可执行文件,当前登录的角色是有执行权限的用户

②linux下可执行文件,如果是在/bin(系统指令如cat,cp等)、/sbin(超级用户指令如:ifconfig等)、/usr/bin(后期安装的软件运行脚本)或者/usr/sbin 里头,就直接敲文件名就可以运行.

注:查看文件是否在系统环境变量中方法

[root@localhost bin]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

 或者使用env查看所有环境变量。

参考自:

GCC -l选项:手动添加链接库

被编译器隐藏的过程_weixin_34161029的博客-CSDN博客

Linux下如何查看环境变量?-linux运维-PHP中文网

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chde2Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值