本文的示例代码

文件层级:

其中,test.c代码:

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

mymath.h中声明相关方法:

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

mymath.c中实现相关方法:

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

编译的整个过程

预处理:在编译之前由预处理器对源码进行的处理。主要包括宏替换、删除注释、执行预处理命令入#include、#ifdef等,生成.i文件。预处理后的文件会比源文件大很多,因为#include执行了复制,就<stdio.h>这个文件就有很多行了。此时文件仍然可以以文稿形式打开。

编译:将源码转化成汇编代码生成.s文件。汇编之后的.s文件都是汇编指令,比如movl、call等。此时文件仍然可以以文稿形式打开。

汇编:将汇编语言转化成机器码,生成.o文件。生成.o文件就是机器码了,不能使用文稿打开。

链接:编译之后的文件还不能直接执行,因为一个项目中存在多个文件,文件之间有引用关系,将这些文件进行关联并最终生成可执行程序的过程就是链接。

备注
宏义上的编译是指程序从源文件到二进制程序的全部过程,该过程包含预处理、编译、汇编、链接三个阶段。或者是从源文件到二进制文件的全过程,也就是生成.o文件的过程,该过程包含预处理、编译、汇编三个阶段。狭隘的编译就只是将.i文件转化成.s文件的过程。通常我们所说的编译就是宏义上的编译。

整个过程的流程图:

Compile Step

备注
有的博客中指出链接后有三种结果,分别是静态库、动态库、可执行文件。这种说法是错误的,动态库是通过gcc编译指令在链接之前生成,静态库的生成是通过ar指令进行打包,所以库是链接过程的参与文件而不是产物。

gcc指令

基本格式:gcc [options] file1 file2...  // 不加入参数时,默认依次执行编译、汇编、链接操作,并生成名为 a.out的可执行文件
常用参数:-E                 // 只执行预处理操作,生成.i文件-S                 // 只执行到编译操作为止,生成的是汇编文件(.s 或 .asm)-c                 // 只执行到汇编为止,不进行链接,生成.o的机器码文件-o filename        // 指定输出地址和文件名-static            // 静态链接-share            // 动态链接,也叫共享链接-g          // 编译时生成debug有关的程序信息(供gdb使用)--save-temps       // 保留中间文件,比如.i、.s、.o文件等-I PATH            // 在指定目录寻找引用文件-lname               // 链接库,其中name为去掉lib前缀和.so/.a后缀后的名字,-l后面不加空格,如-lmysqlclient就是链接libmysqlclient.a的静态库-L PATH            // 优先在指定路径下搜索链接的库文件,不设置时按照默认顺序寻址链接库

完整示例:

gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test

拆解:
-o:将test.o文件以test文件名生成在当前路径
-L:在/usr/dev/mysql/lib下寻找相关的库文件
-l:mysqlclient在对应的路径下有libmysqlclient.so和libmysqlclient.a,使用-l(小写)指令时去掉lib和.so/.a后缀
–static:默认情况下, GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,加上-static选项,强制使用静态链接库。

静态库链接时搜索路径顺序

  1. ld会去找GCC命令中的参数-L
  2. 再找gcc的环境变量LIBRARY_PATH
  3. 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初compile gcc时写在程序内的

动态链接时、执行时搜索路径顺序:

  1. 编译目标代码时指定的动态库搜索路径
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径
  4. 默认的动态库搜索路径/lib
  5. 默认的动态库搜索路径/usr/lib

有关环境变量:
LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径

更多动态库、静态库知识请看:C语言底层原理(二):动态库、静态库

多文件编译

多文件编译的集中方法:
1、将多个文件编译成.o文件之后统一进行链接,并在链接时指定文件地址,示例:
文件夹层级:

指令:

gcc test.o ./inc/mymath.o -o a.out

2、将多个源文件直接使用gcc指令直接生成可执行程序
以本文最初提到的文件层级来执行以下指令:
执行指令:

 gcc test.c ./inc/mymath.c -I ./inc -o a.out

整个cmd过程:

caoxkdembp:C-Compile caoxk$ gcc test.c ./inc/mymath.c -o a.out
test.c:4:10: fatal error: 'mymath.h' file not found
#include "mymath.h"// 自定义头文件^~~~~~~~~~
1 error generated.
caoxkdembp:C-Compile caoxk$ gcc test.c ./inc/mymath.c -I ./inc -o a.out
caoxkdembp:C-Compile caoxk$ ./a.out
a=2, b=3, a+b=5
caoxkdembp:C-Compile caoxk$

3、如果要编译的文件都在同一个目录下,可以用通配符gcc *.c -o 来进行编译

makefile:文件描述了整个工程的编译、连接等规则。对于大型项目而言,可以编写makefile来实现自动编译整个项目中的文件,具体可以了解makefile的编写规则,此处不涉及。

更多文章

C语言底层原理(一):预处理、编译、汇编、链接相关推荐

  1. C语言 程序的翻译 预处理 编译 汇编 链接 #define详解

    1.程序的翻译环境和执行环境 执行环境:所在操作系统的平台 win10 win11 linux 翻译环境:MSVC gcc g++ 你的vs 2019 和2022 是集成开发环境把编辑器编译器全部给你 ...

  2. 【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  3. 『Go 语言底层原理剖析』文末送书

    互联网迅猛发展的数十年时间里,不断面领着各种新的场景与挑战,例如大数据.大规模集群计算.更复杂的网络环境.多核处理器引起对于高并发的需求,云计算,上千万行的服务器代码-- 那些成熟但上了年纪的语言没能 ...

  4. Go语言底层原理剖析

    作者:郑建勋 出版社:电子工业出版社 品牌:博文视点 出版时间:2021-08-01 Go语言底层原理剖析

  5. stm32启动过程、cortex-m3架构、堆栈代码位置、编译汇编链接分析

    分析 一. 寄存器.架构.工作流程 1. 寄存器架构 二 .总线与各个部件之间的关系(主要是I-Code Bus.D-Code Bus.System Bus) 体系结构:哈佛结构与冯诺依曼结构的区别 ...

  6. 反编译与反汇编、C++编译过程,包括预编译--汇编--编译--链接

    参考:C/C++程序编译流程(预处理->编译->汇编->链接) - ProLyn - 博客园 反汇编和反编译的区别_代码小卒_新浪博客 反汇编与反编译: 汇编:是把汇编源程序转变为目 ...

  7. 使用gcc编译和链接C语言程序,用GCC编译链接程序--编译链接器GCC常用功能(菜鸟级)...

    转载自:http://daimajishu.iteye.com/blog/1089740 对gcc认识的一篇文章,就转载了,截取了自己感兴趣部分. 一,GCC编译器简介 虽然我们称Gcc是C语言的编译 ...

  8. c语言编辑编译链接,C语言的“编译、链接”

    我们写的代码,仅仅是文本文件(txt),不管后缀怎么变,终究是文本文件,计算机只能显示,不能做事(执行). 文本文件通过"编译.链接",成为可执行文件(windows下是exe): ...

  9. 深入理解Go底层原理剖析 (送书)

    互联网迅猛发展的数十年时间里,不断面领着各种新的场景与挑战,例如大数据.大规模集群计算.更复杂的网络环境.多核处理器引起对于高并发的需求,云计算,上千万行的服务器代码-- 那些成熟但上了年纪的语言没能 ...

  10. 程序的编译与链接、预处理符号、指令

    程序的编译与链接 1.程序编译 组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code). 每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序. 链 ...

最新文章

  1. Redis源码解析——Zipmap
  2. 聊聊Spring事务失效的12种场景,太坑人了
  3. Solidworks公司电脑图纸被加密之后如何解密输出
  4. oracle巡检 博客,自己总结了一下巡检的工作 for Oracle RAC
  5. Linux文件目录及其作用
  6. 在Oracle中利用SQL_TRACE跟踪SQL的执行
  7. js list删除指定元素_vue.js
  8. minio在不同平台下的启动命令
  9. python全局解释器锁 tensorflow_Python即将出局?Julia和Swift能取而代之吗?
  10. python - super 寻找继承关系
  11. Python多线程好玩弹窗代码
  12. 理解int的存储方式以及二进制编辑器的使用
  13. 国际网页短信平台通道源码搭建软件后台定制-移讯云短信系统
  14. 【OS笔记 9】操作系统内核的功能
  15. 遗传算法,vector
  16. JavaScript实现模板生成大量数据的方法(附代码)
  17. Qt::QLocale
  18. Pandas的panel结构
  19. 台积电2016年6月营收公布:股价飙升创台个股新记录
  20. 漫话:什么是平衡(AVL)树?这应该是把AVL树讲的最好的文章了

热门文章

  1. 我自己对于Netty的疑问
  2. 你所不知道的@ComponentScan注解用法之包路径占位符
  3. JavaScript的==和Java的==比较
  4. [sublime系列文章] sublime text 3构建系统
  5. error C2146: 语法错误: 缺少“;”(在标识符“CRC”的前面) ...\...\MyMethod.h
  6. Lenovo DS存储Linux下ISCSI 多路径映射配置
  7. CLR中的程序集加载
  8. 5、VS2010+ASP.NET MVC4+EF4+JqueryEasyUI+Oracle该项目的开发——使用datagrid做报表
  9. linux PDF转换为SWF
  10. ubuntu下安装配置 JDK7