GCC编译C:C++的四个过程

从源码到可执行程序,经历四个过程: 预处理、编译、汇编和链接,前三步由使用编译器来完成、链接由链接来完成。

  • 编译器将编译工作主要分为预处理,编译和汇编三部
  • 连接器的工作是把各个独立的模块链接为可执行程序
  • 静态链接在编译期完成,动态链接在运行期完成

阶段名 生成文件类型 预处理(

) 生成

文件 编译(

) 生成

文件 汇编(

) 生层

文件 连接(

) 生成

文件

gcc 选项

选项 含义

查看编译器的版本,像是 gcc 执行时的详细过程

输出名为

的文件,这个不能与源文件名称相同

只预处理,不会编译、汇编、链接

只编译,不会汇编、链接

只编译和汇编,不会连接

在编译过程中,除非使用了-E、-S、-C选项(或者编译出错阻止了完整的编译过程),否则最后的步骤都是链接

文件类型

编译器支持许多和C语言程序相关的扩展名,对它们的说明如下:

扩展名 说明 后期操作 命令

程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编 gcc -E test.c -o test.i

C++程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

C++程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

C++程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

C程序预处理输出,可以被编译。可以理解为预处理翻译(

)后的文件 编译、汇编 gcc -s test.i -o test.s

C++程序预处理输出,可以被编译。可以理解为预处理翻译(

)后的文件 编译、汇编

C程序头文件。(为了节省时间,许多源文件会包含相同的头文件,GCC 允许事先编译好头文件,称为”预编译头文件”,它合适情况下自动被用于编译。) 通常不会出现在命令行

汇编语言。 汇编 gcc -c test.s -o test.o

gcc 是 GUN Compiler Collection的缩写。

预处理(pre-processing),E:插入头文件,替换宏,展开宏

gcc -E main.c -o main.i

编译(Compiling)S:编译成汇编

gcc -S main.i –o main.s

汇编(Assembling) c:编译成目标文件

gcc –c main.s –o main.o

链接 (Linking):链接到库中,变成可执行文件

gcc main.o –o main
./main

也可以一次性完成:

gcc main.c –o main

但一般情况下生成.o文件比较好,可以重定位文件,让别人使用

1.1 预处理

  • 处理所有的注释,以空格代替
  • 将所有的 #define删除, 并且展开所有的宏定义
  • 处理条件编译指令 #if, #ifdef, #elif, #else, #endif 处理条件编译指令
  • 处理处理 #include, 展开( evolve)被包含的文件
  • 保留编译器需要使用的 #pragma指令

C语言代码在交给编译器之前,会先由预处理器进行一些文本替换方面的操作,例如宏展开、文件包含、删除部分代码等。

在正常的情况下,GCC 不会保留预处理阶段的输出文件,也即 .i 文件。然而,可以利用 -E 选项保留预处理器的输出文件,以用于诊断代码。-E选项指示 GCC 在预处理完毕之后即可停止。

a、默认情况下,预处理器的输出会被导入到标准输出流(也就是控制台)

gcc -E main.c

b、可以利用-o选项把它导入到某个输出文件

gcc -E main.c -o main.i
 gcc -E main.c > main.i

表示把预处理的结果导出到 main.i 文件中。

c、使用 -C 选项阻止预处理器删除源文件和头文件中的注释。

注意,这里是大写的 -C,不是小写的 -c。小写的 -c 表示只编译不链接。

gcc -E -C main.c -o main.i

对比之前的输出,可以发现,保留愿文件中的注释

1.2 编译阶段

  • 对预处理文件进行一系列词法分析,语法分析和语义分析
  • 词法分析主要分析关健字,标示符,立即数等是否合法
  • 语法分析主要分析表达式是否遵循语法规则
  • 语义分析在语法分析的基础上进一步分析表达式是否合法
  • 分析结束后进行代码优化生成相应的汇编代码文件

编译器的核心任务是把C程序翻译成机器的汇编语言(assembly language)。

汇编语言是人类可以阅读的编程语言,也是相当接近实际机器码的语言。每种 CPU 架构都有不同的汇编语言。

实际上,GCC 是一个适合多种 CPU 架构的编译器,不会把C程序语句直接翻译成目标机器的汇编语言,而是在输入语言和输出汇编语言之间,利用一个中间语言,称为 RegisterTransfer Language(简称 RTL,寄存器传输语言)。借助于这个抽象层,在任何背景下,编译器可以选择最经济的方式对给定的操作编码。

通常情况下,GCC 把汇编语言输出存储到临时文件中,并且在汇编器执行完后立刻删除它们。但是可以使用-S选项,让编译程序在生成汇编语言输出之后立刻停止,而不删除临时文件。

-S可以理解为 Save 或者 Stop,自己的理解仅供参考记忆。

如果没有指定输出文件名,那么采用 -S选项的 GCC 编译过程会为每个被编译的输入文件生成以.s作为后缀的汇编语言文件。如下例所示:

gcc -S ts.c

编译器预处理 ts.c,将其翻译成汇编语言,并将结果存储在 ts.s 文件中,可以用文本编辑器察看.

指定输出文件名

gcc -S main.i -o filename.s

1.3 汇编阶段

  • 汇编器将汇编代码转变为机器可以执行的指令
  • 每个汇编语句几乎都对应一条机器指令

目标文件是一种中间文件或者临时文件,如果不设置该选项,gcc 一般不会保留目标文件,可执行文件生成完成后就自动删除了。

注意,使用-c选项表示只编译源文件,而不进行链接,因此,对于链接中的错误是无法发现的。

比如,调用一个不存在的函数,编译器会提示的错误。但是该命令不会输出错误信息。

gcc -c main.s -o main.o

-c选项:只编译不链接,仅生成目标文件。

1.4 链接阶段

gcc main.o -o main.exe

连接器的主要作用是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确的衔接

静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,不过静态链接生成的程序比较大。

动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。

动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。

这里用的clang/clang++ 分四步编译main.c/main.cpp文件

2.1 预处理

clang++ -E main.cpp -o main.ii

2.2 编译阶段,生成汇编

clang++ -S main.ii -o main.s

2.3 汇编阶段,生成目标文件

 clang++ -c main.s -o mian.o

2.4 连接阶段

 clang++ mian.o -o main

2.5 执行

 ./main

2.6 源文件

#include

int main() {
    std::cout << "Hello Biter !" << std::endl;
    return 0;
}

2.7 四部曲之一步到胃

clang++在编译的过程中,保存所有编译过程中产生的文件

2.8 产生中间文件

 clang++ -save-temps main.cpp -o main

2.9 不保存中间文件

 clang++  main.cpp -o main
  • 头文件
//
// Created by langkechanxin on 2021/1/7.

//

#define MAX(a,b) (((a)>(b)) ? (a) : (b))

int g_global = 10;
  • 源文件
//
// Created by langkechanxin on 2021/1/7.

//
#include "test.h"

#define LOW  0
#define HIGH 255

int max(int a, int b)
{
    return MAX(a,b);
}

int main()
{

    int c = max(LOW, HIGH); // Call max to get the larger number

    return 0;
}

预处理

gcc -E test.c -o test.i
gcc -S test.i -o test.s
gcc -c test.s -o test.o

此时,借助 -c选项,生成的中间产物 test.o ,此文件为二级制文件, &#x901A;&#x8FC7; ls -l命令查看一下文件大小:

-rw-r–r– 1 binny staff 912B Jan 7 15:41 test.o

借助二进制文件查看器,比如 UltraEdit 可以查看到地址范围: 00000000h00000390(不包含)这是下一个字节的地址编号。一共 390hB=912B.

Original: https://www.cnblogs.com/burner/p/gcc-bian-yiccde-si-ge-guo-cheng.html
Author: 浪客禅心
Title: GCC编译C:C++的四个过程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606582/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 如何正确地使用Entity Framework Database First

    毕设依旧在不紧不慢地以每天解决一个问题的进度进行中。今天遇到的问题就是在建立数据模型时遇到的。因为项目是基于数据库构建的,所以理所应当地采用DB First来构造实体类和DbCon…

    Linux 2023年6月14日
    0102
  • Apache Shiro 身份验证绕过漏洞 (CVE-2020-1957)

    一、漏洞描述 Apache Shiro 是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理。 在具有 Spring 动态控制器的 1.5.2 之前…

    Linux 2023年6月13日
    0129
  • 面试连环炮系列(二十️五):RocketMQ怎么保证消息不丢失

    A. 从Producer的视角来看:如果消息未能正确的存储在MQ中,或者消费者未能正确的消费到这条消息,都是消息丢失。 B. 从Broker的视角来看:如果消息已经存在Broker…

    Linux 2023年6月6日
    0139
  • 访问权限控制

    一.编译单元 1-1 概念 一个Java源代码文件通常被称为一个编译单元,每个编译单元的后缀需是.java,并且每个编译单元中最多只能有1个public类(当然,可以为0个)。 1…

    Linux 2023年6月8日
    0104
  • zabbix用户,角色,权限,模板管理

    zabbix用户,角色,权限,模板管理 zabbix用户,角色,权限,模板管理 用户组用户角色右上角是创建角色用户lnh@1234使用刚才创建的用户登录模板组模板模板的监控项可以自…

    Linux 2023年6月6日
    0106
  • SQL实战——03. 查找各个部门当前(to_date=’9999-01-01′)领导当前薪水详情以及其对应部门编号dept_no

    查找各个部门当前(to_date=’9999-01-01′)领导当前薪水详情以及其对应部门编号dept_noCREATE TABLE dept_manage…

    Linux 2023年6月14日
    099
  • Android下获取FPS的几种方法

    FPS(Frames Per Second)是关乎Android用户体验最为重要的指标之一,而在VR中更是如此。为了评估VR系统、VR SDK及Unity应用的性能,通常会实时获取…

    Linux 2023年6月7日
    091
  • Android进阶技术之——一文吃透Android的消息机制

    前言 为什么要老药换新汤 作为Android中 至关重要 的机制之一,十多年来,分析它的文章不断,大量的内容已经被挖掘过了。所以: 已经对这一机制熟稔于心的读者,在这篇文章中,看不…

    Linux 2023年6月13日
    096
  • 防火墙NAT配置与DHCP下发

    该实验如果有做的不足的地方请见谅 实验目标: 按要求划分区域,公司内部办公区为trust,服务器区为dmz,外部网络为untrust。 PC1和PC2为公司内部办公区,需要从防火墙…

    Linux 2023年6月7日
    0104
  • 如何在shell脚本中传变量的值传给curl

    随着即时通讯的发展,大量的报警媒介已经从以往的邮件转为钉钉,企业微信等聊天工具。当我使用shell脚本来监控 Keepalived的时候,在给curl传递变量的时候无法生效,经过查…

    Linux 2023年6月8日
    087
  • GDT表实现

    GDT是保护模式下的内存段登记表。 段界限计算 段界限用 20 个二进制位来表示。只不过此段界限只是个单位量,它的单位要么是字节,要么是 4K,这是由描述符中的G位来指 定的。由于…

    Linux 2023年6月7日
    080
  • vue axios的二次封装

    1、axios的二次封装 BiliBili作者原地址,多多支持 npm i axios //下载axios 首先创建两个文件夹在src目录下;api和config 先在 confi…

    Linux 2023年6月7日
    075
  • eMule电骡使用教程

    eMule(电骡)是一个不错的下载器。实际上它是一个文件分享平台,但你可以把它当做一个自带资源搜索的bt下载器,如下图。虽然用户不多(我下午看在线有10万),下载速度一般,比较好的…

    Linux 2023年6月6日
    0138
  • 工作三年的一些感悟

    前言 很久没有上博客,我是看着其中一篇文章进来,然后正好我也加起来三年,那就提笔写一下感触,出来三年基本上和有些同学断了联系,唯有室友还偶尔还会聊上几句,三年做过游戏测试、社交AP…

    Linux 2023年6月8日
    098
  • 什么?Android上面跑Linux?

    前言 众所周知,现在程序员因为工作、个人兴趣等对各种系统的需求越来越大,部分人电脑做的还是双系统。其中,比较常见的有各种模拟器、虚拟机在windows上面跑Android、Linu…

    Linux 2023年5月27日
    083
  • Linux 程序后台运行 ☞ nohup

    nohup(no hang up),可以使程序在系统后台运行,即使退出终端也不受影响。 安装教程: CSDN: Linux 安装nohup 常见问题 执行jar包时: ignori…

    Linux 2023年6月14日
    0105
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球