C Cpp Compile
What are c/cpp
c面向过程,cpp面向对象。cpp几乎完全兼容c的标准语法,而反之不行。
What do compilers do
TL;DR
Translate c/cpp programs wrote in “human languages” in to 0/1 machine language. This progress include:
- Preprocess: process #include, #define, where the compiler simply replace the lines with corresponding files or scripts.(From
.c/.cppto.i/.ii) - Compiling: do grammar check, parsing and translate the scripts into assembly language(
.s) - Assembly: translate assembly language into 0/1 machine language(
.o/.obj) - Linking: assemble full program with third-party libs and other files.(
.exe/.out)
Detailed description
Preprocess
可以认为这一步是简单的字面查找替换:
- 把
#include <iostream>或者#include 'my_header.h替换成对应文件的完整内容。 - 把宏定义
#define定义的常量和宏函数替换 - 处理
#ifdef,#ifndef等条件编译指令。 - 删掉注释。
这一阶段编译器不会去管变量,语法之类的东西,完全是字符串级别的查找替换。这也就是为什么写宏定义的时候我们需要加很多括号,因为这种傻瓜替换并不会管你替换完的语句是否有歧义。 仅仅5行的程序
//main.cpp
#include <iostream> //这是一个cpp标准库文件
int main(){
std::cout << "hello world";
return 0;
}
经过了预处理 gcc -E main.cpp -o main.i之后变成了3万多行,因为把整个iostream头文件复制粘贴了进来。
Compilation
对预处理后的代码进行语法和词法分析,优化后翻译成汇编语言。
- 这一步会进行优化,也就是编译参数
-O1,-O2之类的发挥作用的地。比如删去冗余代码,展开循环,等。 - 对不同的CPU架构,汇编语言指令集不同。
gcc -S main.i -o main.s
这一步之后,上面生成的非常臃肿的文件又变得简洁了,因为头文件中那些没有别调用的冗余部分被删除了。
Assembly
把汇编代码翻译成机器码。
gcc -c main.s -o main.o
这一步之后就变成二进制文件了。