a.cpp
b.cpp
extern
By using 'extern', you are telling the compiler that whatever follows it will be found (non-static) at link time; don't reserve anything for it in the current pass since it will be encountered later. Functions and variables are treated equally in this regard.
这大概是说:添加extern声明,可以让编译器把“寻找定义”这件事情推迟到链接阶段,而不会在编译阶段报“没有定义”的错误。
#include <b.h>
b.h
对于“在a.cpp文件中使用在b.cpp中定义的 (全局)变量 ”这种场景,我们不常见到。推荐的实现方式如下:
//a.cpp #include <b.h> int main(){ int a= b + 1; }
//b.h extern b;
//b.cpp #include <b.h> int b = 5;
如果直接在b.h中定义变量b,那么b会在所有include了<b.h>的cpp文件中被定义。这会导致b被多次定义。因此,采用上面的这种实现方式,可以确保b只在b.cpp中被定义一次,其他cpp文件均在链接阶段链接到这个定义。
b
<b.h>
不要在.h文件中直接定义或声明变量。前者会导致重定义错误,后者会导致歧义(详见此处)。
在CPP文件中include C头文件时,需要使用extern "C"。(详见此处) 例如:
extern "C"
#ifdef __cplusplus extern "C" { #endif #include "b.h" #ifdef __cplusplus } #endif
这里b.h是一个C头文件,不是CPP头文件。这样做的原因如下:
假设b.c中定义了函数int b(int,int)。由于C语言没有函数重载这一特性,因此b.c编译成的b.o文件中,这个函数的符号名可能类似于_b。但对于同名的CPP函数,它在.o文件中的符号名会类似于_b_int_int。因此,如果我们直接认为b.h是一个CPP头文件,那么我们无法在链接时正确地找到相应的函数实现。
b.c
int b(int,int)
b.o
_b
.o
_b_int_int
注:在extern后面添加大括号,其效果是对大括号内的每条语句都添加extern前缀;#include "b.h"语句会在前处理时被替换为b.h中的内容。因此这里相当于对b.h中的每条声明都添加了extern前缀。
#include "b.h"