翻译单元
- 源文件 + 头文件(直接/间接)- 应该忽略的预处理语句
- 源文件所引用的所有头文件都会展开在该源文件中进行编译
一处定义原则
- 程序级:一般函数
- 翻译单元级:内联函数、类、模板(虽然可以在整个程序中有多处定义,但是需要保证一模一样)
- 因为编译期是以翻译单元为单位进行编译的,而上面三种类型的代码需要有具体的定义才能正常编译,光有声明是不够的。
- 这也是为什么Eigen全是头文件,因为它全是模板类,没办法定义在源文件中。链接
流程
- 预处理:file.cc -> file.i
-
gcc -E ./main.cpp -o ./main.i
- 将源文件转换为翻译单元的过程
- 防止头文件被循环展开
- ifdef
- pragma once(推荐,用ifdef如果后面的文件宏写错了(比如两个不同h文件的宏写成一样了),那就只会include其中一个头文件)。
-
- 编译:file.i -> file.s
-
g++ main.i -S -o main.s
- 将翻译单元转换为相应的汇编语言表示(汇编语言还是有符号表示的)
- 编译优化
- 增量编译 V.S. 全部编译
- 有时候只修改了头文件,增量编译不知道需要重新编译,这时候就需要全部编译
-
- 汇编:file.s -> file.o
-
g++ main.s -c -o main.o
- 将汇编语言进一步转化为机器语言(二进制文件,看不到任何符号表示)
-
- 链接:file.o -> file.exe
- g++ main.o -S -o main
- 合并多个目标文件,关联声明与定义
- 种类:内部链接、外部链接、无链接
- 常见错误:找不到定义