C语言编译过程详解

C语言编译的五大过程详解 前言 说实话,很多人做了很久的C/C++,也用了很多IDE,但是对于可执行程序的底层生成一片茫然,这无疑是一种悲哀,可以想象到大公司面试正好被问到这样的问题,有多悲催不言而喻,这里正由于换工作的缘故,所以打算系统的把之前用到的C/C++补一补。 总述 从一个源文件(.c)到可执行程序到底经历了哪几步,我想大多数的人都知道,到时到底每一步都做了什么,我估计也没多少人能够说得清清楚楚,明明白白。 ... 阅读详情

原文链接https://www.cnblogs.com/CarpenterLee/p/5994681.html

前言

C语言程序从源代码到二进制行程序都经历了那些过程?本文以Linux下C语言的编译过程为例,讲解C语言程序的编译过程。

编写hello world C程序:

// hello.c
#include <stdio.h>
int main(){
    printf("hello world!\n");
}

编译过程只需:

$ gcc hello.c # 编译
$ ./a.out # 执行
hello world!

这个过程如此熟悉,以至于大家觉得编译事件很简单的事。事实真的如此吗?我们来细看一下C语言的编译过程到底是怎样的。

上述gcc命令其实依次执行了四步操作:1.预处理(Preprocessing), 2.编译(Compilation), 3.汇编(Assemble), 4.链接(Linking)。

 

示例

为了下面步骤讲解的方便,我们需要一个稍微复杂一点的例子。假设我们自己定义了一个头文件mymath.h,实现一些自己的数学函数,并把具体实现放在mymath.c当中。然后写一个test.c程序使用这些函数。程序目录结构如下:

├── test.c
└── inc
    ├── mymath.h
    └── mymath.c

程序代码如下:

// test.c
#include <stdio.h>
#include "mymath.h"// 自定义头文件
int main(){
    int a = 2;
    int b = 3;
    int sum = add(a, b); 
    printf("a=%d, b=%d, a+b=%d\n", a, b, sum);
}

头文件定义:

// mymath.h
#ifndef MYMATH_H
#define MYMATH_H
int add(int a, int b);
int sum(int a, int b);
#endif

头文件实现:

// mymath.c
int add(int a, int b){
	return a+b;
}
int sub(int a, int b){
	return a-b;
}

1.预处理(Preprocessing)

预处理用于将所有的#include头文件以及宏定义替换成其真正的内容,预处理之后得到的仍然是文本文件,但文件体积会大很多。gcc的预处理是预处理器cpp来完成的,你可以通过如下命令对test.c进行预处理:

gcc -E -I./inc test.c -o test.i

或者直接调用cpp命令

$ cpp test.c -I./inc -o test.i

上述命令中-E是让编译器在预处理之后就退出,不进行后续编译过程;-I指定头文件目录,这里指定的是我们自定义的头文件目录;-o指定输出文件名。

经过预处理之后代码体积会大很多:

X文件名文件大小代码行数
预处理前test.c146B9
预处理后test.i17691B857

预处理之后的程序还是文本,可以用文本编辑器打开。

2.编译(Compilation)

这里的编译不是指程序从源文件到二进制程序的全部过程,而是指将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程。编译的指定如下:

$ gcc -S -I./inc test.c -o test.s

上述命令中-S让编译器在编译之后停止,不进行后续过程。编译过程完成后,将生成程序的汇编代码test.s,这也是文本文件,内容如下:

// test.c汇编之后的结果test.s
    .file   "test.c"
    .section    .rodata
.LC0:
    .string "a=%d, b=%d, a+b=%d\n"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    movl    $2, 20(%esp)
    movl    $3, 24(%esp)
    movl    24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    20(%esp), %eax
    movl    %eax, (%esp)
    call    add 
    movl    %eax, 28(%esp)
    movl    28(%esp), %eax
    movl    %eax, 12(%esp)
    movl    24(%esp), %eax
    movl    %eax, 8(%esp)
    movl    20(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $.LC0, (%esp)
    call    printf
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret 
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

请不要问我上述代码是什么意思!-_-

3.汇编(Assemble)

汇编过程将上一步的汇编代码转换成机器码(machine code),这一步产生的文件叫做目标文件,是二进制格式。gcc汇编过程通过as命令完成:

$ as test.s -o test.o

等价于:

gcc -c test.s -o test.o

这一步会为每一个源文件产生一个目标文件。因此mymath.c也需要产生一个mymath.o文件

4.链接(Linking)

链接过程将多个目标文以及所需的库文件(.so等)链接成最终的可执行文件(executable file)。

命令大致如下:

$ ld -o test.out test.o inc/mymath.o ...libraries...

结语

经过以上分析,我们发现编译过程并不像想象的那么简单,而是要经过预处理、编译、汇编、链接。尽管我们平时使用gcc命令的时候没有关心中间结果,但每次程序的编译都少不了这几个步骤。也不用为上述繁琐过程而烦恼,因为你仍然可以:

$ gcc hello.c # 编译
$ ./a.out # 执行

参考文献

1.https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
2.http://www.trilithium.com/johan/2005/08/linux-gate/
3.https://gcc.gnu.org/onlinedocs/gccint/Collect2.html

【C语言】C语言 4 个编译过程详解 c 编译过程将作为输入的源代码转换为目标代码或机器代码。编译过程可分为预处理、编译、汇编和链接四个步骤。 阅读详情

相关推荐

解密Android相机框架:从HAL到应用层的全链路解析

本文深入解析Android相机框架的全链路架构,从应用层到硬件抽象层(HAL)再到驱动层,详细介绍了CamX-CHI架构的设计哲学与实战应用。通过HAL3接口、V4L2交互机制及Camera2 API的最佳实践,帮助开发者优化相机性能,解决多摄切换、预览卡顿等常见问题,提升成像效率与稳定性。

weixin_29238147的博客 408

C语言编译过程

1、C语言编译过程 2、单c文件编译实践 3、多c文件编译实践 4、define 5、选择性编译ifdef、ifndef、if 6、静态库和动态链接库

michael_linux的博客,一个小小小学生。滴水穿石,步步为营,只为那刹那芳华。 7428

Ansys Zemax导入CAD文件避坑指南:STL/STEP/IGES格式选择与性能优化

本文深度解析了在Ansys Zemax中导入CAD文件的核心要点与性能优化策略。针对STL、STEP、IGES等主流格式,详细对比了其几何表示、精度与适用场景差异,并提供了基于模型特征的格式选择决策树。文章重点分享了体元、弦公差等高级参数的调优技巧,以及处理复杂装配体和避免精度陷阱的实战指南,旨在帮助光学工程师提升仿真效率与结果可靠性。

weixin_29202687的博客 436

C语言编译原理

暂时先出一期,简单讲解下c语言是怎么从文本文件变成机器中的动作的。

qq_52479948的博客 5415

2025-08-19利用opencv检测图片中文字及图片的坐标

该代码实现了图片中中文文本的检测与位置计算功能。主要使用CnOcr库进行OCR识别,结合OpenCV和PIL库处理图像。功能包括:1)检测图片中的中文文本及位置坐标;2)计算每个文本的像素宽度和高度;3)在原图上绘制文本边界框并标注识别结果。代码通过put_chinese_text函数解决中文显示问题,最终输出各文本内容、坐标位置及尺寸信息。适用于需要获取图片中文字精确位置的应用场景。

m0_58149406的博客 394

树莓派与OpenCV实现人脸识别(OpenCV安装篇)

主要看了以下两位博客的文章完成的,也遇到了不少的坑,在这里一一填补说明。 链接: https://blog.youkuaiyun.com/weixin_42163073/article/details/107308759. 链接: https://blog.youkuaiyun.com/weixin_42573595/article/details/108526850. 树莓派与OpenCV实现人脸识别(OpenCV安装篇)一、材料准备:二、系统烧录三、安装OpenCV依赖项四、下载OpenCV-4.3.0五、为OpenCV配置P

weixin_45880057的博客 1万+

【C语言编译】编译原理和详细过程

重定位是链接器的。

张壮壮的博客 3098

在Centos上从零开始部署并运行TinyWebServer服务器,过程记录(非常详细)

TinyWebServer是个什么项目?它是Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器。使用线程池+非阻塞socket+epoll(ET和LT均实现) +事件处理(Reactor和模拟Proactor均实现) 的并发模型使用状态机解析HTTP请求报文,支持解析GET和POST请求访问服务器数据库实现web端用户注册、登录功能,可以请求服务器图片和视频文件实现同步/异步日志系统,记录服务器运行状态。......

AnChenliang_1002的博客 3021

c语言编译过程

它会解析目标文件中的各个符号(函数名、变量名等),将其地址进行分配,同时还会进行符号的重定位,以确保不同目标文件之间的引用关系正确。总体来说,编译过程的目标是将高级语言转换为机器码,以实现程序的执行。预处理(Preprocessing):预处理器会处理源代码中以"#"开头的预处理指令,例如#include和#define等,将它们替换为相应的内容。它会对源代码进行词法分析和语法分析,生成一颗抽象语法树(Abstract Syntax Tree,AST),然后进行语义分析和优化,最终生成相应的汇编代码。

https://github.com/cv70 3617

摩尔线程嵌入式面试题及参考答案(2万字长文)

说一下你对 drm 框架的理解。 DRM(Direct Rendering Manager)是 Linux 系统中用于管理图形显示设备的一个重要框架。 从架构层面来讲,它处于内核空间,主要目的是为用户空间的图形应用程序提供一个统一的接口来访问图形硬件。DRM 包括内核态的驱动模块和用户态的库。内核态的驱动负责和硬件进行交互,比如对显存的管理、硬件寄存器的配置等。用户态的库则方便应用程序利用内核态提供的功能进行图形渲染等操作。 在图形显示的具体流程中,DRM 可以控制显示设备的分辨率、刷

大模型大数据攻城狮的专栏 1229

基于STM32+ESP8266+手机APP的心率血氧温湿度监测报警系统设计(项目资料ID:18)

基于 STM32 微控制器、ESP8266 无线模块和 QT 手机 APP 的多参数监测报警系统。该系统可实时采集心率、血氧饱和度、环境温湿度等参数,通过 OLED 显示屏本地显示,并通过 WiFi 模块上传至手机 APP 实现远程监测与数据可视化。系统具备报警阈值自定义功能,当参数超出设定范围时,通过蜂鸣器和 LED 进行声光报警。系统以 STM32F103 为控制核心,采用 MAX30102 传感器采集心率和血氧,DHT20 采集温湿度,通过 ESP8266 实现无线通信,配合 QT 开发的手机 APP

以培养嵌入式工程师为己任 1万+

c语言的编译过程详解

c语言的编译过程详解 IDE的使用让很多和我一样的人对C/C++可执行程序的底层生成一知半解,不利于我们深入理解原理。在这里小结一下,望路过的大神指正~ 前言:从一个源文件(.c文件)到可执行程序到底经历了哪几步,我想很多人都知道,但是每一步具体做了什么,估计很多像我一样的人就不能说的清清楚楚,明明白白了。 C语言编译过程分成四个步骤: 1,由.c文件到.i文件,这个过程叫预处理 2,由.i文件到.s文件,这个过程叫编译 3,由.s文件到.o文件,这个过程叫汇编 4,由.o文件到可执行文件,这个过程叫链接

jimin是我老公的博客 7297

【CAN总线测试】——通讯相关诊断测试

本章主要介绍通讯相关诊断测试用例设计

LOVE135149的博客 1813

C语言程序编译过程详解

C语言的编译过程就是把我们可以理解的高级语言代码转换为计算机可以理解的机器代码的过程,其实就是一个翻译的过程。1.预处理2.编译3.汇编4.链接下面两张图就是C程序编译的完整过程接下来我们看看编译过程不同阶段在做什么。1. 预处理编译过程的第一步就是预处理,与处理结束后会产生一个后缀位(.i)的临时文件,这一步由预处理器完成。删除所有的注释宏扩展文件包含预处理器会在编译过程中删除所有注释,因为注释不属于程序代码,它们对程序的运行没有特别作用。

qq_40569221的博客 4441

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

详解C语言编译过程

本文以"Hello, World!"程序为例,通过gcc -v命令详细解析C语言编译的四个核心阶段。首先展示了从1.c源文件到可执行文件bin的完整编译过程,包括预处理、编译、汇编和链接四个步骤。通过分析gcc输出的详细日志,揭示了每个阶段调用的具体工具(如cc1、as、collect2等)及其参数配置,展示了头文件搜索路径、中间文件生成等关键信息。最后通过链接器将目标文件和系统库合并生成最终可执行程序,完整呈现了C语言从源代码到二进制文件的转换过程。

weixin_52297807的博客 1175

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C语言编译过程总结详解

C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。过程图解如下:         从图上可以看到,整个代码的编译过程分为编译和链接两个过程,编译对应图中的

cike211的专栏 1017

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

c语言编译过程详解

为什么我们编写的C语言要进行编译?什么是编译?编译时发生了什么? 机器无法理解我们编写的C语言,而编译就是将面向人类的高级语言转换成为面向机器的机器语言的过程,图1是GCC编译器进行编译的过程,编译时主要分为了4个阶段,每个阶段的具体作用将在接下来进行介绍。

指尖动听知识库 397
上一篇: Windows 内存泄漏检测工具——LeakDiag
下一篇: C++全局静态变量初始化顺序
Jee1009
博客等级 码龄12年 12粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值