以下是标准的相关部分。请参阅标准文本下方的解释:
§6.9.2/2 外部对象定义
具有文件范围的对象的标识符声明没有初始化程序,并且没有存储类说明符或具有存储类说明符 static,构成暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,则行为与翻译单元包含该标识符的文件范围声明完全相同,复合类型为翻译单元的末尾,初始化器等于 0。
ISO C99 §6.9/5 外部定义
外部定义是一个外部声明,它也是函数(内联定义除外)或对象的定义。如果用外部链接声明的标识符在表达式中使用(而不是作为结果为整数常量的 sizeof 运算符的操作数的一部分),则在整个程序的某处,该标识符应该只有一个外部定义;否则,不得超过一个。
在 C 版本中,“g”全局变量被“合并”为一个,因此最终您将只有一个被声明两次。这没关系,因为当时不需要 extern,或者可能没有退出。因此,这是出于历史和兼容性原因构建旧代码。这是此旧功能的gcc 扩展。
它基本上使 gcc 为名为“a”的变量分配内存,因此可以有多个声明,但只有一个定义。这就是为什么下面的代码即使使用 gcc 也不起作用的原因。
这也称为暂定定义。C++ 没有这样的东西,那就是在它编译的时候。C++ 没有临时声明的概念。
暂定定义是没有存储类说明符和初始化程序的任何外部数据声明。如果到达翻译单元的末尾并且没有出现带有标识符初始值设定项的定义,则暂定定义将成为完整定义。在这种情况下,编译器会为定义的对象保留未初始化的空间。
但是请注意,即使使用 gcc,以下代码也不会编译,因为这不再是带有分配值的暂定定义/声明:
在文件“ac/a.cpp”中
int a = 1;
在文件“bc/b.cpp”中
int a = 2;
int main() { return 0; }
让我们用更多的例子来超越这个。以下陈述显示了正常定义和暂定定义。请注意,静态会有所不同,因为那是文件范围,不再是外部的。
int i1 = 10; /* definition, external linkage */
static int i2 = 20; /* definition, internal linkage */
extern int i3 = 30; /* definition, external linkage */
int i4; /* tentative definition, external linkage */
static int i5; /* tentative definition, internal linkage */
int i1; /* valid tentative definition */
int i2; /* not legal, linkage disagreement with previous */
int i3; /* valid tentative definition */
int i4; /* valid tentative definition */
int i5; /* not legal, linkage disagreement with previous */
更多详细信息可以在以下页面上:
http://c0x.coding-guidelines.com/6.9.2.html
另请参阅此博客文章以获取更多详细信息:
http://ninjalj.blogspot.co.uk/2011/10/tentative-definitions-in-c.html