...
#include "test1.h"
int main(..)
{
count << aaa <<endl;
}
aaa
中定义的test1.h
,我没有使用extern关键字,但仍然可以引用aaa
。
所以我怀疑extern
真的有必要吗?
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
也被重载并且 - 根据上下文 - 控制或不控制链接。它所做的另一件事是控制对象的生命周期(“静态生命周期”)。但是在全局范围内,所有变量都已经有一个静态的生命周期,有些人认为回收控制链接的关键字是个好主意(这只是我的猜测)。
链接基本上是在“命名空间范围”中声明/定义的对象或函数的属性。如果它具有内部链接,则其他翻译单元将无法通过名称直接访问它。如果它具有外部链接,则在所有翻译单元中应该只有一个定义(有例外,请参阅一个定义规则)。
我发现组织数据的最佳方法是遵循两个简单的规则:
通过声明,我的意思是通知编译器事物存在,但不要为它们分配存储空间。这包括typedef
、struct
等extern
。
通过定义,我通常是指“为”分配空间,int
等等。
如果你有这样的一行:
int aaa;
在头文件中,每个编译单元(基本上定义为编译器的输入流 - C 文件以及它以#include
递归方式引入的所有内容)都将获得自己的副本。如果您将定义了相同符号的两个目标文件链接在一起,那将导致问题(除非在某些有限的情况下,例如const
)。
一个更好的方法是在你的一个 C 文件中定义该aaa
变量,然后输入:
extern int aaa;
在你的头文件中。
请注意,如果您的头文件只包含在一个 C 文件中,这不是问题。但是,在那种情况下,我什至可能没有头文件。在我看来,头文件仅用于在编译单元之间共享内容。
如果您的 test1.h 有 aaa 的定义,并且您想将头文件包含到多个翻译单元中,您将遇到多个定义错误,除非 aaa 是常量。最好在 cpp 文件中定义 aaa 并在头文件中添加 extern 定义,该定义可以作为头文件添加到其他文件中。
头文件中变量和常量的拇指规则
extern int a ;//Data declarations
const float pi = 3.141593 ;//Constant definitions
由于常量在 C++ 中具有内部链接,因此在翻译单元中定义的任何常量都不会对其他翻译单元可见,但对于具有外部链接的变量来说,情况并非如此,即它们对其他翻译单元可见。将变量的定义放在头文件中,在其他翻译单元中共享会导致变量的多次定义,从而导致多次定义错误。
在那种情况下,extern
是没有必要的。当符号在另一个编译单元中声明时,需要 extern。
当您使用#include
预处理指令时,包含的文件将被复制出来以代替指令。在这种情况下,您不需要extern
,因为编译器已经知道aaa
.
如果 aaa 未在另一个编译单元中定义,则不需要 extern,否则需要。