编译单元
每一个.cpp对应一个编译单元,当然包括其#include的头文件。
头文件中应该只包含声明,对应的.cpp文件放定义: extern
test1.h
#ifndef AAA
#define AAA
//上面的声明有什么用?
//若下面的函数fun()不为extern,则会在link阶段出错,显示main.obj中已经有了fun(),test.obj再重复就出错了。
void fun();
void fun2();
extern int a;
#endif
#include "test1.h"
#include<iostream>
void fun()
{
std::cout << "fun()\n";
}
void fun2()
{
fun();
}
int a = 1;
#include "test1.h"
int main()
{
fun();
return 0;
}
上面的test1.h只包含声明,如果在其中定义如 int a = 1; 那么将会产生链接错误。
在vs2010下错误如下
error C2374: 'a' : redefinition; multiple initialization
因为有2个.cpp文件,产生了2个编译单元,如果在.h定义了全局变量a的话,每个编译单元都包含一个a的符号变量,当链接时将在data segment产生同一个a变量,产生名字冲突。而只在.h中声明,如 extern int a;
那么可以看出只有在test1.cpp中有定义,那么只有test1.obj这个编译单元中有a这个符号,也就不会产生名字冲突。
可以查看test1.obj和main.obj, 只有test1.obj中有a这个符号。
///////////////////////////////////////////////////////
#ifndef 在上面例子中当在.h中有a的定义时为什么没有阻止每个编译单元都生成一个a
百度百科相关解释
详细讨论#ifndef的作用
在c语言中,对同一个变量或者函数进行多次声明是不会报错的。所以如果h文件里只是进行了声明工作,即使不使用# ifndef宏定义,多个c文件包含同一个h文件也不会报错。 但是在c++语言中,#ifndef的作用域只是在单个文件中。所以如果h文件里定义了全局变量,即使采用#ifndef宏定义,一个c文件包含同一个h文件多次还是会出现全局变量重定义的错误。 使用#ifndef可以避免下面这种错误:如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错误。////////
关键是 #ifndef的作用域只是在单个文件中
要记住 : 如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错误。
test2.h
#ifndef _TEST_2_H_
#define _TEST_2_H_
char *fun2();
int a = 1;
#endif
test3.h
#include "test2.h"
char *fun3();
test2.cpp
#include "test2.h"
#include "test3.h"
char *fun2()
{
return "fun()\n";
}
char *fun3()
{
return "fun2()\n";
}
'a' : redefinition; multiple initialization