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 . 检测源文件的语法合法性 ...
随机推荐
- Oracle中Instr用法
在项目中用到了Oracle中 Instr 这个函数,顺便仔细的再次学习了一下这个知识. Oracle中,可以使用 Instr 函数对某个字符串进行判断,判断其是否含有指定的字符. 其语法为:Instr ...
- DTree的改进与使用经验
1.dtree.js源码 function Node(id, pid, name, url, title, target, icon, iconOpen, open) { this.id = id; ...
- 《mahout实战》
<mahout实战> 基本信息 原书名:Mahout in action 作者: (美)Sean Owen Robin Anil Ted Dunning Ellen Fr ...
- JAVA常见算法题(三十四)---计算加密之后的电话号码
某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的, 加密规则如下: 每位数字都加上5,然后用和除以10的余数代替该数字, 再将第一位和第四位交换,第二位和第三位交换. 求加密之后的 ...
- 怎样通过terminal得到AWS EC2 instance的ip
可得到private ip,也是本地的ip.事实上通过ifconfig也能得到: GET http://169.254.169.254/latest/meta-data/local-ipv4 公共ip ...
- scala的一些特殊用法
1.创建多行字符串,只要把多行字符串放在3个双引号间("""...""")即可.这是Scala对于here document,或者叫here ...
- there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
建表语句: create table test_table( id integer not null auto_increment primary key, stamp_created tim ...
- 结合实例详解"pure Virtual function called"
作者:阿波 链接:http://blog.csdn.net/livelylittlefish/article/details/9750593 (4年前的一篇文章,翻出来共享一下.) 本实例即为经典的讲 ...
- ElementUI的提示框的使用记录
1.popover点击之后隐藏 问题描述:做了一个通知面板功能,下面提示信息有路由,每次点击消息呢,就跳转到了路由页面,但是此时这个面板没关闭,希望将其关闭 解决:官方文档有个属性 <div&g ...
- Mac下Sublime Text 总是以新窗口打开文件的解决办法
Mac下的Sublime有个毛病,经常打开后,之前打开的窗口都没了,太难受了. Windows/Linux下的sublime总是默认的以标签页的形式打开关联的文件,但是在Mac下使用Sublime打开 ...