- 我们都知道无论是用C或者C++来开发程序,用各种IDE来开发即省时又省力 因为IDE已经帮我们做好了编译过程,隐藏了很多细节. 以至于我们对整个过程一无所知.今天我们就来看下编译的过程.
- C语言的编译大致分为四部:
- 总结
C语言的真正编译过程
我们都知道无论是用C或者C++来开发程序,用各种IDE来开发即省时又省力 因为IDE已经帮我们做好了编译过程,隐藏了很多细节. 以至于我们对整个过程一无所知.今天我们就来看下编译的过程.
C语言的编译大致分为四部:
- 预处理
- 把源代码翻译成汇编语言
- 把汇编语言翻译成二进制文件
- 链接
我们分部来看下每一步都做了什么
准备源码文件 hello.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("hello world!\n");
return 0;
}
1. 预处理
gcc -E hello.c -o a.c可以生成预处理后的文件。
通过查看文件内容和文件大小可以得知a.c讲stdio.h和stdlib.h包含了进来
预处理过程实质上是处理“#”,将#include包含的头文件直接拷贝到hello.c当中;将#define定义的宏进行替换,同时将代码中没用的注释部分删除等
具体做的事儿如下:
(1)将所有的#define删除,并且展开所有的宏定义。说白了就是字符替换
(2)处理所有的条件编译指令,#ifdef #ifndef #endif等,就是带#的那些
(3)处理#include,将#include指向的文件插入到该行处
(4)删除所有注释
(5)添加行号和文件标示,这样的在调试和编译出错的时候才知道是是哪个文件的哪一行
(6)保留#pragma编译器指令,因为编译器需要使用它们.(#pragma once 防止重复引用头文件)
可以查看生成的a.c文件,把所有的include的文件插入进指定的位置. 所有宏都已经展开
2. 把源代码翻译成汇编语言
gcc -S hello.c -o a.s可以生成汇编代码
(1)词法分析,
(2)语法分析
(3)语义分析
(4)优化后生成相应的汇编代码
1 .file "hello.c"
2 .section .rodata
3 .LC0:
4 .string "hello world!"
5 .text
6 .globl main
7 .type main, @function
8 main:
9 .LFB0:
10 .cfi_startproc
11 pushl %ebp
12 .cfi_def_cfa_offset 8
13 .cfi_offset 5, -8
14 movl %esp, %ebp
15 .cfi_def_cfa_register 5
16 andl $-16, %esp
17 subl $16, %esp
18 movl $.LC0, (%esp)
19 call puts
20 movl $0, %eax
21 leave
22 .cfi_restore 5
23 .cfi_def_cfa 4, 4
24 ret
25 .cfi_endproc
26 .LFE0:
27 .size main, .-main
28 .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
29 .section .note.GNU-stack,"",@progbits
3. 把汇编语言翻译成二进制文件
gcc -c hello.c -o a.o 类Uinx系统编译的结果生生成.o文件,Windows系统是生成.obj文件
计算机只识别二进制文件
4. 链接
gcc hello.c -o main 直接输出文件
就像刚才的hello.c它使用到了C标准库的东西“printf”,但是编译过程只是把源文件翻译成二进制而已,这个二进制还不能直接执行,这个时候就需要做一个动作,将翻译成的二进制与需要用到库绑定在一块
举个例子,像printf函数是系统定义的函数,有系统库,我们只是做了一个动作,把库文件和我们的文件做了一个链接: 可以通过ldd的指令查看
pxwen@pxwen-Think:~/Workstation/cmake/studycmake$ ldd main
linux-vdso.so.1 => (0x00007ffcacb9d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd1e3828000)
/lib64/ld-linux-x86-64.so.2 (0x000055931be8f000)
可以看到是和系统下的库做了一个链接
总结
其实我们直接可以gcc hello.c 就可以输出一个在Linux下的可执行文件, 我只是把这个过程做了一个分步,希望大家看的更清楚一点. gcc hello.c 其实是把这四个步骤合并了,希望对大家有点帮助。