C-从源文件到可执行文件的详细编译链接过程
一直用windows一键搞定, 没有去了解详细的编译链接过程, 今天看了一篇文章, 顺便实验和记录在Linux下逐步生成的步骤.
预处理: 执行#include, #define, #if, #ifdef等预处理指令 把宏展开
编译: 把源文件编译为汇编语言文件 对所有常量表达式(只包含常量的表达式)求值发生在此阶段(不是预处理阶段)
汇编: 把汇编语言文件翻译称为机器语言指令
链接: 连接器就负责处理合并各种用到的*.o, 比如用到的printf函数就会连接printf.o, 结果就得到一个可执行文件, 可以被加载到内存中由系统执行
先说下gcc常用选项
--version: 查看gcc版本号及版权信息
-x language: 指明使用的编程语言, 允许的语言包括c、c++、assembler none, ‘none’意味着恢复默认行为, 即根据文件的扩展名猜测源文件的语言
-o: *输出到指定文件 (与其他选项配合生成指定步骤下的文件)
-E: *仅做预处理, 不进行编译、汇编和链接, 即执行#include, #define, #if, #ifdef等预处理指令
-S: *仅编译到汇编语言, 不进行汇编和链接, 即把源文件翻译为汇编语言
-c: *编译、汇编到目标代码(目标代码可不是执行文件), 不进行链接, 从-E、-S到-c命令执行的步骤范围从小到大
-pipe: 使用管道代替临时文件
-combine: 将多个源文件一次性传递给汇编器
**如果不指定参数则自动执行预处理、编译到汇编语言、汇编到目标代码、链接生成可执行文件**
-l library或者-llibrary: 进行链接时搜索名为library的库, gcc hello.c -lm -o hello
-Idir: 把dir加入到搜索头文件的路径列表中, gcc hello.c -I../inc -o hello
-Ldir: 把dir加入到搜索库文件的路径列表中, gcc -I/home/foo -L/home/foo -ltest test.c -o test
-g: 表示在生成的目标文件中带调试信息, 调试信息可以在程序异常中止产生core后, 帮助分析错误产生的源头, 包括产生错误的文件名和行号等非常多有用的信息
-Wall: 会打开一些很有用的警告选项, 建议编译时加此选项
-w: 禁止显示所有警告信息
先来个hello world
#include <stdio.h>
main() {
printf("Hello World!\n");
}
将上面内容保存为hello.c, 并通过gcc去编译它
gcc -g -Wall hello.c -o hello
执行完上述语句后程序会报错

hello.c:3: warning: return type defaults to ‘int’ /*当函数没有设置返回值类型的时候, C语言默认程序返回的是int类型*/
hello.c:5: warning: control reaches end of non-void function /*警告: 在有返回值的函数中, 控制流程到达函数尾 [-Wreturn-type]*/
解决上述问题的方法很简单, 代码如下
#include <stdio.h>
int main() {
printf("Hello World!\n");
return ;
}
再次执行gcc -g -Wall hello.c -o hello

下面就来详细讲解整个编译过程

上图是一个hello的c程序由gcc编译器从源码文件hello.c中读取内容并将其翻译成为一个可执行的对象文件hello的过程, 这个过程包含了几个阶段:
1.预处理过程
预处理根据以字符#开头的命令修改原始的C程序, 比如hello.c中的第一行的#include <stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容, 插入到程序文本中, 结果就得到里另一个C程序, 通常是以*.i作为文件扩展名
可通过如下指令获得gcc -E hello.c -o hello.i

用记事本打开hello.i可以看到如下代码(注意行数)


可以看到除了#include <stdio>指令之外, 其他指令均未被改变
2.编译阶段(即把源文件转为汇编语言): 编译器将文本文件hello.i翻译成文本文件hello.s, 它包含一个汇编语言程序, 汇编语言程序中的每条语句都以一种标准的文件格式确切地描述了一条低级机器语言指令
可通过如下指令获得: gcc -S hello.c -o hello.s
打开hello.s可以看到

3.汇编阶段(把汇编代码翻译称为机器语言指令): 汇编器将hello.s翻译成机器语言指令, 把这些指令打包成一种可重定位目标程序的格式, 并把结果保存在hello.o中, hello.o是一个二进制文件, 它的字节编码是机器语言指令, 而不是字符
可通过如下指令获得: gcc -c hello.c, 最终生成的hello.o文件需要使用objdump打开, 具体指令为: objdump -d hello.o, 所查看到的内容为

4.链接阶段: hello.c程序中调用了printf函数, 而printf函数存在于一个名为printf.o的单独的预编译好的目标文件中, 而这个文件必须以某种方式合并到我们的hello.o程序中, 连接器就负责处理这种合并, 结果就得到hello文件, 它是一个可执行文件, 可以被加载到内存中由系统执行
使用的指令为: gcc hello.o -o hello, 最终生成了一个hello文件, 同样此hello文件可用通过objdump打开: objdump -d hello
经过上面四个过程, 我们就可以把一个源代码文件编译成机器能运行的可执行文件, 这个可执行文件刚开始是保存在磁盘上, 当计算机要运行这个程序的时候, hello就被加载到内存中, 接着程序指令被不断复制到寄存器中由CPU来执行, 最后把”hello world”从寄存器中打到显示设备上, 这就是hello程序整个执行过程
参考: http://blogread.cn/it/article/6492?f=wb1
C-从源文件到可执行文件的详细编译链接过程的更多相关文章
- [转]C++编译链接过程详解
C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接是把目标文件.操作 ...
- 转:C语言的编译链接过程的介绍
11:42:30 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接 ...
- GCC编译链接过程
编译链接过程 代码 #cat main.c #include <stdio.h> int add(int x, int y); int sub(int x, int y); int mul ...
- C/C++编译链接过程详解
有些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错误信息不能定位到某 ...
- 转:从编译链接过程解析static函数的用法
关于static函数的用法 就像我们熟知的那样,变量可以分全局的和局部的,函数也可以分全局的和局部的. 比如说,在一个工程的common.h中定义了一个全局变量 int test;那么在整个工程的作用 ...
- 【对象模型】C++模版的编译链接过程——编译器真的会检查所有tocken层面的错误么?
模版(template)设计的初衷,是设计一种自动实例化机制,不需要使用者参与,编译器可根据使用者提供的模版参数再套用类的定义来实例化.所谓实例化,除了包含对于程序变量的实例化,即开辟空间并设置某些变 ...
- Delphi编译/链接过程
下面展示了Delphi是怎样编译源文件,并且把它们链接起来,最终形成可执行文件. 当Delphi编译项目(Project)时,将编译项目源文件.窗体单元和其他相关单元,在这个过程中将会发生好几件事情: ...
- Delphi 编译/链接过程
- OC-01 编译链接的作用
编译:检测代码的语法合法性,随后生成.o文件. 链接:把项目中所有的.out合并,生成一个可执行文件. OC编译连接过程 .m---->.o---->.out . 检测源文件的语法合法性 ...
随机推荐
- WebLogic Server 12c相对JBoss EAP 6的优势
原文来自:https://blogs.oracle.com/middlewareplace/entry/why_should_you_choose_oracle 1.多数据中心部署和集群 WebLog ...
- tomcat sso 配置
源: http://www.oecp.cn/hi/single/blog/349 为了实现单点登录,做了个CAS SSO单点登录实例,经过反复的琢磨和修改终于成功了,现将CAS SSO单点登录实例详细 ...
- selectHelper
转:适有修改并调试OK var Sys = (function (ua) { var s = {}; s.IE = ua.match(/msie ([\d.]+)/) ? true : false; ...
- LZO 使用和介绍
LZO说明 摘要 LZO 是一个用 ANSI C 语言编写的无损压缩库.他能够提供非常快速的压缩和解压功能.解压并不需要内存的支持.即使使用非常大的压缩比例进行缓慢压缩出的数据,依然能够非常快速的解压 ...
- zoj 2860 四边形优化dp
Breaking Strings Time Limit: 2 Seconds Memory Limit: 65536 KB A certain string-processing lan ...
- Multi-label && Multi-label classification
Multi-label classification with Keras In today’s blog post you learned how to perform multi-label cl ...
- 动态图片 Movie android-gif-drawable GifView
Movie 类 文档位置:/sdk/docs/reference/android/graphics/Movie.html 官方对这个类连一句介绍都没有,并且所有的方法也没有一行注释,可见多么不受重视! ...
- CSS深入了解border:利用border画三角形等图形
三角形实际上是border的产物 我们正常使用的border都是四边一个颜色,当我们把四边换上不同颜色 那么你就会发现,三角来了~! <!DOCTYPE html> <html la ...
- Android生成带图片的二维码
一.问题描述 在开发中需要将信息转换为二维码存储并要求带有公司的logo,我们知道Google的Zxing开源项目就很好的帮助我们实现条形码.二维码的生成和解析,但带有logo的官网并没有提供demo ...
- 消息队列的使用场景(转载c)
作者:ScienJus链接:https://www.zhihu.com/question/34243607/answer/58314162来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业 ...