C/C++ 多文件编译笔记
 
 
 
 
 
 
 
 
 
 
 
贡献者: addis
以下规则对 c 和 c++ 语言都适用。
1. 单个 translation unit
-
#include
头文件(.h)相当于直接把头文件的内容插入到当前位置。
- 头文件可以没有或者有任意后缀名(例如标准库的头文件就没有后缀名)。
- 每个 .cpp(也可以用 .cxx)文件叫做一个 translation unit。可以单独编译成一个 object 文件(.o)
- 某个 translation unit 中定义的宏只在这一个 translation unit 中有效,即从定义开始到文件底部(或者到
#undef
)。
- 头文件开始用
#pragma once
可以防止同一个头文件被多次插入同一个 translation unit。例如 b.h
和 c.h
中都 include 了 a.h
,如果 cpp 文件中同时 include 了 b.h
和 c.h
,a.h
就不会被插入两次。注意这并不是 C++ 标准,但大部分编译器都实现了。
2. 多个 translation unit
- 若有多个 translation unit,可以分别编译,然后将所有 object 文件 link 起来就成了可执行程序。
- 一个 translation unit 中定义的函数要在另一个 translation unit 调用前要先声明(declare)。
- 每个 translation unit 编译的时候也不需要有其他 translation unit 存在,即使调用了其他 translation unit 中定义的函数。
- 只有在 link 阶段编译器才会检查一个 o 文件中调用的函数是否能在另一个 o 文件中有定义,如果没有,link 就会失败。
- ODR(one definition rule) 要求一个函数不能在同一个或不同 translation unit 中有重复的定义(definition),例如全局变量和函数(包括成员函数)。但重复的声明(declaration)是允许的。
- inline 函数或变量需要在使用到它的每个 translation unit 中都有一样的定义(所以一般放到头文件中)。否则即使预先 declare 也会出错。
- C++17 开始支持
inline
的全局变量,这相当于在一个 TU 中定义,其他 TU 中声明,这样就可以在头文件中定义全局变量。
-
class
的声明也需要在使用到它的每个 translation unit 中都有一样的定义(所以一般放到头文件中)。
- 任何函数或类的 template 的定义同样也需要在使用到它的每个 translation unit 中都有一样的定义(所以一般放到头文件中)。
-
inline
的含义已经与是否真的 inline
几乎无关了,只是为了避免 ODR 错误的一种手段。
- 即使使用了
inline
,同一个 translation unit 中也不可以出现两个同样的定义。
- 如果一个函数调用的函数在它之后定义,则需要将 declaration 放在它前面。
- 所以编译时若提示找不到某个函数,一定要注意是 compile 过程中没找到还是 link 过程中没找到。如果是后者可能是没有 link 到适当的库(
-l
选项)。无论是静态还是动态库,就相当于是编译好的 .o 文件打包好。
- 另一个避免 ODR 的方法是用
static
关键词让其具有 internal linkage。这样它就只在当前的 TU 中生效,linker 看不见它。这样就可以在不同 TU 中给同名函数或变量用不同的定义。这(有点)相当于不用 static
,但命名成不同的变量或函数。如果制作成 .a
或者 .so
库,使用者同样也不能用它们。
-
const
的全局变量可以放在头文件中,同样具有 local linkage,在每个 TU 中都有一个独立的对象,不违反 ODR。
 
 
 
 
 
 
 
 
 
 
 
© 小时科技 保留一切权利