认识编译器和C/C++编译

一. 编译器

编译器也是一种程序,其作用是将一种语言翻译为另一种语言,通常是将高级语言翻译为低级语言,或者说是将源代码翻译成能被计算机或虚拟机执行的目标代码。

编译器的主要工作流程是:源代码-预处理器-编译器-目标代码-链接器-可执行文件

另一个角度的工作流程:词法分析-语法分析-语义分析-中间代码生成-代码优化-目标代码生成-目标代码优化

编译器的种类

“本地”编译器

用来生成与编译器本身所在环境操作系统(平台)相同的环境运行的目标代码的编译器叫“本地”编译器。

“交叉”编译器

生成用来在其他平台上运行的目标代码,这种编译器叫做“交叉”编译器。这个过程也叫交叉编译。

例如:在 Mac 上编译能在 Android 上运行的 so , 这个过程就属于交叉编译。

编译器的前后端

以中间代码生成步骤为中心划分:

  • 与源语言有关,与目标语言无关的部分叫做编译器前端
  • 和目标语言有关,和源语言无关的部分叫做编译器后端

将编译器分为前端和后端,对编译技术的起到了一定作用。

二. GNU & GCC & Clang & llvm

1. GNU

GNU, Gnu's Not Unix 的缩写。由于一开始 Unix 系统是商业收费的,理查德·斯托曼提出 GNU 计划,希望发展出一套完整的开放源代码操作系统来取代 Unix,名为 GNU 。

1989 年,GNU 项目中编辑器、编译器、shell 等都已完成,唯独缺了操作系统核心,所以开始正式发展 Hurd 来作为 GNU 计划的操作系统。

1991 年,Linux 出现, GNU 项目的软件可在 Linux 上运行。

1992 年,Linux 和 GNU 结合,形成完全自由的操作系统,称为 GNU/Linux 简称 Linux 。此时 Hurd 还没完善,被抛弃。

2. GCC

gcc, GNU C Compiler 的缩写,是 GNU 项目的编译器部分,也是类 Unix 和 Mac OS X 操作系统的标准编译器。

gcc 原本只处理 C 语言,后来也发展成可处理 Object-c、Java 、C++。

g++

gcc 和 g++ 都是 GNU 的编译器。他们的区别如下:

  • 对于 .c ,gcc 把它当作 C 程序,而 g++ 当作 C++ 程序;对于 .cpp , gcc 和 g++ 都会当作 c++ 程序。

对于 .cpp 的编译链接
gcc 和 g++ 都可以编译,而链接可以用 g++ 或者gcc -lstdc++。因为 gcc 命令不能自动和 C++ 程序使用的库联接,所以通常使用 -lstdc++ 来完成联接。

3. Clang

Clang 是一个 C、C++、Objective-C 和 Objective-C++ 编程语言的编译器前端。它采用了底层虚拟机(LLVM)作为其后端。这个软件项目是由苹果发起的,目标是替代 GNU 的 gcc 编译器套装。

因为 gcc 的编译器慢慢无法满足苹果的需求,因此,苹果开发了 Clang 与LLVM来完全取代 gcc,Xcode4 之后,苹果的默认编译器已经是 Clang/LLVM 。Clang 作为编译器前端,LLVM 作为编译器后端。

4. MinGw

MinGw 是 Minimalist GNU for Windows 的缩写。它是一个可自由使用和自由发布的 Windows 特定头文件和使用 GNU 工具集导入库的集合,允许在 Windows 平台生成本地的 Windows 程序而不需要第三方 C 运行时(C Runtime)库。

三. C/C++ 编译过程

C/C++ 编译过程可以分为四个步骤:

  • 预处理
  • 编译
  • 汇编
  • 链接

1.预处理

预处理是处理文件中的预处理命令,通常是 # 开头,预处理通常包含如下步骤:

  • 替换宏定义 #define
  • 处理条件预编译指令如 #if
  • 处理 #include 指令,将需要包含的文件递归包含进来
  • 等等

可以使用 -E 命令执行预处理操作,-o 表示生成的文件,最终生成 .i 文件

gcc -E -o test.i test.c


例如:有 test.h test.c 文件

>>test.h
int func(int a,int b) {
    return a + b;
}

>>test.c 

#include "test.h"
#define A 1
#define B 2
int main() {
    
    int c = func(A,B);
}

执行 gcc -E -o test.i test.c

>> 生成的 test.i

# 1 "test.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 363 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "test.c" 2

# 1 "./test.h" 1


int func(int a,int b) {
    return a + b;
}
# 3 "test.c" 2


int main() {

    int c = func(1,2);
}

2. 编译

编译的过程是将经过处理之后的程序转换成特定汇编语言代码的过程,可以使用 -E 命令执行编译操作,其表示让编译器编译之后停止,不进行后续步骤。

gcc -S -o test.s test.c

>> 汇编代码:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 15    sdk_version 10, 15, 4
    .globl  _func                   ## -- Begin function func
    .p2align    4, 0x90
_func:                                  ## @func
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %eax
    addl    -8(%rbp), %eax
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $1, %edi
    movl    $2, %esi
    callq   _func
    xorl    %ecx, %ecx
    movl    %eax, -4(%rbp)
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function

.subsections_via_symbols

3.汇编

汇编是将上述汇编代码转换为机器码,这一步产生的文件叫做目标文件,是二进制格式。每一个源文件都会产生一个 .o 的目标文件。

as test.s -o test.o

等价于

gcc –c test.c –o test.o

>> 这里就不贴

4.链接

链接过程是将目标文件以及所需的库文件,链接成最终的 .out 可执行文件。链接程序的主要工作就是将有关的 .o 的目标文件彼此相连接,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

>> 执行
gcc test.c

生成 a.out 的可执行文件

在 mac 上执行 ./a.out 可运行文件

四. 静态链接和动态链接

静态链接

静态链接:在链接阶段,将汇编生成的目标文件 .o 与引用到的库一起链接打包进可执行文件中。就是在编译链接时直接将需要的执行代码拷贝到调用处,因此允许的时候存在多份内存拷贝。

静态链接库:一组目标文件的的集合,即很多目标文件经过压缩后打包形成一个文件 .a

静态链接库的特点:

  • 静态库对函数库的链接是放在编译时期完成的
  • 程序在运行的时候与函数库无关
  • 浪费内存,多个地方调用某个函数就存在多次拷贝

动态链接

就是在编译的时候不直接拷贝可执行的代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中。

然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。

动态链接库的特点:

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 多个程序可以共享同一段代码,而不需要在内存上存储多个拷贝,
  • 缺点是由于是运行时加载,可能会影响程序的前期执行性能。
不同操作系统下编译过程文件的后缀
系统 源文件 目标文件 动态链接库 静态链接库 可执行文件
windows .c/.cpp .obj .dll .lib .exe
Linux .c/.cpp .o .so .a .out/coff/elf (没有后缀)
Mac OS X .c/.cpp .o .dylib .a .out/coff/elf (没有后缀)
参考文章

编译器
编译器(GNU & GCC & clang & llvm)
C语言编译过程详解
Linux 中的动态链接库和静态链接库是干什么的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352