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)

大家都在看

  • docker的基本使用

    一、 实验前置知识 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是…

    Linux 2023年6月13日
    086
  • redis订阅关闭异常解决

    redis订阅关闭异常解决 应用程序模块订阅redis运行一段时间出现一直重连Redis服务,日志如下: 2019-04-28 10:06:17,551 ERROR org.spr…

    Linux 2023年5月28日
    0115
  • 【证券从业】金融基础知识-第四章 股票01

    注1:后续学习并整理到第八章,全书完结后再合并成一个笔记进行源文件分享 注2:本章内容巨多,大约分为三篇文章记录消化 posted @2022-06-05 00:25 陈景中 阅读…

    Linux 2023年6月13日
    0108
  • python学习

    python中的字符串以双引号或者单引号表示 长度为L:第一个字节索引为0或-L 最后一个字节索引为L-1或-1 in是二元关系操作,用来判断左侧内容是否在右侧的集合中 float…

    Linux 2023年6月6日
    0105
  • Linux巡检脚本

    #!/bin/bash sys:centos6.x/7.x [ $(id -u) -ne 0 ] && echo "&#x8BF7;&#x…

    Linux 2023年6月6日
    099
  • 【总结】瞬时高并发(秒杀/活动)Redis方案

    1,Redis 丰富的数据结构(Data Structures) * 字符串(String) – Redis字符串能包含 任意类型的数据 一个字符串类型的值最多能存储 …

    Linux 2023年5月28日
    091
  • Centos7 离线安装K3s

    1、安装前准备 github地址:https://github.com/k3s-io/k3s/releases k3s二进制文件:k3s下载地址:github地址 / 百度网盘地址…

    Linux 2023年6月7日
    0142
  • Linux基线加固

    bash;gutter:true; 1、修改vsftp回显信息 (1)检查办法 修改vsftp回显信息: 需在安装VSFTP的情况下检查,未安装可忽略或禁用该项。 查看ftpd_b…

    Linux 2023年6月13日
    090
  • Android 图片设置圆角

    Android 开发中,经常需要对图片进行二次处理,比如添加圆角效果 或 显示圆形图片; 通过第三方框架 Glide 设置圆角效果; 写法1: RequestOptions opt…

    Linux 2023年6月13日
    092
  • 一文聊透 Netty IO 事件的编排利器 pipeline | 详解所有 IO 事件的触发时机以及传播路径

    欢迎关注公众号:bin的技术小屋,本文图片加载不出来的话可查看公众号原文 本系列Netty源码解析文章基于 4.1.56.Final版本 1. 前文回顾 在前边的系列文章中,笔者为…

    Linux 2023年6月6日
    0101
  • 【电子取证:FTK Imager篇】DD、E01系统镜像仿真

    星河滚烫,人生有理想!​—【suy999】 一、DD、E01系统镜像动态仿真 在电子取证分析过程中,我们经常遇到DD、E01等系统镜像,然而,并非所有工作者手边都有自动…

    Linux 2023年6月13日
    0113
  • 聊聊Netty那些事儿之从内核角度看IO模型

    从今天开始我们来聊聊Netty的那些事儿,我们都知道Netty是一个高性能异步事件驱动的网络框架。 它的设计异常优雅简洁,扩展性高,稳定性强。拥有非常详细完整的用户文档。 同时内置…

    Linux 2023年6月6日
    092
  • Redis和Memcache

    redis 和memcached都支持集群 Redis支持的数据类型要丰富得多,Redis不仅仅支持简单的k/v类型的数据,同时还提供String,List,Set,Hash,So…

    Linux 2023年5月28日
    0100
  • 时钟周期,机器周期和指令周期

    有些概念没有搞清楚,基础不牢呀。 保持更新;https://github.com/yaowenxu posted @2022-02-16 16:18 xuyaowen 阅读(42 …

    Linux 2023年6月14日
    0107
  • Linux系统下安装tomcat步骤

    说明:jdk自动安装后路径是/usr/lib/jvm 在”vim /etc/profile”修改profile文件尾部 unset -f pathmunge…

    Linux 2023年6月6日
    085
  • 在Windows平台用Visual C++ 2022 (v143)编译PDCurses

    综述 PDCurses是一个开源的跨平台curses库,它提供了一组函数,开发者可以用这组函数在终端(Console、Terminal)上设置光标的位置和字符的显示样式。本文介绍在…

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