少于 1 分钟阅读

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:

  1. Preprocess: process #include, #define, where the compiler simply replace the lines with corresponding files or scripts.(From .c/.cpp to .i/.ii)
  2. Compiling: do grammar check, parsing and translate the scripts into assembly language(.s)
  3. Assembly: translate assembly language into 0/1 machine language(.o/.obj)
  4. Linking: assemble full program with third-party libs and other files.(.exe/.out)

Detailed description

Preprocess

可以认为这一步是简单的字面查找替换:

  1. #include <iostream> 或者 #include 'my_header.h 替换成对应文件的完整内容。
  2. 把宏定义 #define定义的常量和宏函数替换
  3. 处理 #ifdef, #ifndef等条件编译指令。
  4. 删掉注释。

这一阶段编译器不会去管变量,语法之类的东西,完全是字符串级别的查找替换。这也就是为什么写宏定义的时候我们需要加很多括号,因为这种傻瓜替换并不会管你替换完的语句是否有歧义。 仅仅5行的程序

//main.cpp
#include <iostream> //这是一个cpp标准库文件
int main(){
	std::cout << "hello world";
	return 0;
}

经过了预处理 gcc -E main.cpp -o main.i之后变成了3万多行,因为把整个iostream头文件复制粘贴了进来。

Compilation

对预处理后的代码进行语法和词法分析,优化后翻译成汇编语言。

  1. 这一步会进行优化,也就是编译参数 -O1,-O2之类的发挥作用的地。比如删去冗余代码,展开循环,等。
  2. 对不同的CPU架构,汇编语言指令集不同。

gcc -S main.i -o main.s 这一步之后,上面生成的非常臃肿的文件又变得简洁了,因为头文件中那些没有别调用的冗余部分被删除了。

Assembly

把汇编代码翻译成机器码。

gcc -c main.s -o main.o 这一步之后就变成二进制文件了。

更新时间: