...
#include "test1.h"
int main(..)
{
count << aaa <<endl;
}
aaa
在test1.h
中定义,我没有使用extern关键字,但仍可以引用aaa
。
所以我怀疑extern
真的有必要吗?
答案 0 :(得分:12)
extern
有其用途。但它主要涉及不满意的“全球变量”。 extern
背后的主要思想是用外部联系声明事物。因此,它与static
相反。但在许多情况下,外部链接是默认链接,因此在这些情况下您不需要extern
。 extern
的另一个用途是:它可以将定义转换为声明。例子:
extern int i; // Declaration of i with external linkage
// (only tells the compiler about the existence of i)
int i; // Definition of i with external linkage
// (actually reserves memory, should not be in a header file)
const int f = 3; // Definition of f with internal linkage (due to const)
// (This applies to C++ only, not C. In C f would have
// external linkage.) In C++ it's perfectly fine to put
// somethibng like this into a header file.
extern const int g; // Declaration of g with external linkage
// could be placed into a header file
extern const int g = 3; // Definition of g with external linkage
// Not supposed to be in a header file
static int t; // Definition of t with internal linkage.
// may appear anywhere. Every translation unit that
// has a line like this has its very own t object.
你知道,它相当复杂。有两个正交的概念:联系(外部与内部)以及声明与定义的关系。 extern
关键字可以影响两者。关于联系,它与static
相反。但是static
的含义也是重载的 - 并且 - 取决于上下文 - 是否控制链接。它的另一个作用是控制对象的生命周期(“静态生命周期”)。但是在全球范围内,所有变量都已经具有静态生命周期,并且有些人认为回收关键字以控制链接是个好主意(这只是猜测)。
Linkage基本上是在“命名空间范围”声明/定义的对象或函数的属性。如果它具有内部链接,则不能通过其他翻译单元的名称直接访问它。如果它具有外部链接,则所有翻译单元中只应有一个定义(有例外,请参阅单定义规则)。
答案 1 :(得分:7)
我发现组织数据的最佳方法是遵循两个简单的规则:
通过声明,我的意思是通知编译器存在的东西,但不为它们分配存储空间。其中包括typedef
,struct
,extern
等等。
通过定义,我通常意味着“为{分配空间”,如int
等等。
如果你有一行:
int aaa;
在头文件中,每个编译单元(基本上定义为编译器的输入流 - C文件及其带有#include
的所有内容,递归)将得到它自己的副本。如果将两个具有相同符号定义的目标文件链接在一起(除了在某些有限的情况下,如const
),这将导致问题。
更好的方法是在你的一个C文件中定义aaa
变量,然后放入:
extern int aaa;
在你的头文件中。
请注意,如果您的头文件仅包含在一个C文件中,则这不是问题。但是,在这种情况下,我可能甚至没有头文件。在我看来,头文件仅用于在编译单元之间共享内容。
答案 2 :(得分:5)
如果你的test1.h有aaa的定义并且你想将头文件包含到多个翻译单元中,你将遇到多个定义错误,除非aaa是常量。 最好在cpp文件中定义aaa,并在头文件中添加extern定义,可以作为标题添加到其他文件中。
在头文件中具有变量和常量的Thumb规则
extern int a ;//Data declarations
const float pi = 3.141593 ;//Constant definitions
由于常量在c ++中具有内部链接,因此在翻译单元中定义的任何常量对于其他翻译单元是不可见的,但对于变量而言它们不具有外部链接,即,它们对于其他翻译单元是可见的。将变量的定义放在标题中,在其他翻译单元中共享将导致变量的多个定义,从而导致多个定义错误。
答案 3 :(得分:3)
在这种情况下,extern
不是必需的。当符号在另一个编译单元中声明时,需要使用Extern。
使用#include
预处理指令时,将复制包含的文件来代替该指令。在这种情况下,您不需要extern
,因为编译器已经知道aaa
。
答案 4 :(得分:1)
如果aaa没有在另一个编译单元中定义,则不需要extern,否则就行了。