一直用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-从源文件到可执行文件的详细编译链接过程的更多相关文章

  1. [转]C++编译链接过程详解

    C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接是把目标文件.操作 ...

  2. 转:C语言的编译链接过程的介绍

    11:42:30 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接 ...

  3. GCC编译链接过程

    编译链接过程 代码 #cat main.c #include <stdio.h> int add(int x, int y); int sub(int x, int y); int mul ...

  4. C/C++编译链接过程详解

    有些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错误信息不能定位到某 ...

  5. 转:从编译链接过程解析static函数的用法

    关于static函数的用法 就像我们熟知的那样,变量可以分全局的和局部的,函数也可以分全局的和局部的. 比如说,在一个工程的common.h中定义了一个全局变量 int test;那么在整个工程的作用 ...

  6. 【对象模型】C++模版的编译链接过程——编译器真的会检查所有tocken层面的错误么?

    模版(template)设计的初衷,是设计一种自动实例化机制,不需要使用者参与,编译器可根据使用者提供的模版参数再套用类的定义来实例化.所谓实例化,除了包含对于程序变量的实例化,即开辟空间并设置某些变 ...

  7. Delphi编译/链接过程

    下面展示了Delphi是怎样编译源文件,并且把它们链接起来,最终形成可执行文件. 当Delphi编译项目(Project)时,将编译项目源文件.窗体单元和其他相关单元,在这个过程中将会发生好几件事情: ...

  8. Delphi 编译/链接过程

     

  9. OC-01 编译链接的作用

    编译:检测代码的语法合法性,随后生成.o文件. 链接:把项目中所有的.out合并,生成一个可执行文件. OC编译连接过程 .m---->.o---->.out  . 检测源文件的语法合法性 ...

随机推荐

  1. PHP 7.0 5.6 下安裝 phpLDAPadmin 发生错误的修正方法

    在稍具規模的網路環境中, 網管時常選用 LDAP 來進行帳號的統整管理, 一方面提供管理便利度, 另一方面使用者也不必因為不同系統而記憶不同帳號, phpLDAPadmin 是一套常見的 LDAP 管 ...

  2. 如何优化JAVA代码

    通过使用一些辅助性工具来找到程序中的瓶颈,然后就可以对瓶颈部分的代码进行优化.一般有两种方案:即优化代码或更改设计方法.我们一般会选择后者,因为不去调用以下代码要比调用一些优化的代码更能提高程序的性能 ...

  3. kafak-python函数使用详解

    Consumer是非线程安全的 Kafka只保证消息不漏,即at lease once,而不保证消息不重.关键点:假如consumer挂了重启,那它将从committed offset位置(告诉ser ...

  4. Informatica 常用组件Aggregator之一 聚合表达式

    转换类型:已连接.主动        聚合转换允许您执行聚合计算,比如平均值和总和.聚合转换与表达式转换不同,您可以使用聚合转换对多组执行计算.而表达式转换只允许您逐行地执行计算.        使用 ...

  5. Web项目添加Maven支持

    很多时候,进入到某个项目组,并非项目刚刚开始:同样,很多时候,项目并非一开始就有Maven支持: 对现有的项目支持Maven,需要修改以下地方: 1. 将以下代码拷贝到工程根路径下的  .projec ...

  6. Java基础(十二):包(package)

    一.Java 包(package): 为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间.包的作用: 1.把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用. 2.如同文件夹 ...

  7. 理解JavaScript里this关键字

    1.全局代码中的this:始终指向window 2.函数代码中的this: }; var bar = { x: , test: function () { alert(this === bar); a ...

  8. mysql 数据库远程访问设置方法

    摘自: http://www.iteye.com/topic/418151 mysql数据库远程访问设置方法 1.修改localhost更改 "mysql" 数据库里的 " ...

  9. 【小程序】component使用

    component使用 组件模板 组件模板的写法与页面模板相同.组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上. 在组件模板中可以提供一个 <slot> 节点,用于承载组 ...

  10. OleView.exe:查看机器上的COM 组件。

      OleView.exe可以查看机器上安装的所有COM组件的类别以及各个类别下的COM组件.