c++ - C和C++中的全局变量有什么区别?

标签 c++ c gcc global-variables

我已经测试了以下代码:

在文件 a.c/a.cpp

int a;

在文件 b.c/b.cpp

int a;
int main() { return 0; }

当我用gcc *.c -o test编译源文件时,它成功了。

但是当我用 g++ *.c -o test 编译源文件时,它失败了:

ccIJdJPe.o:b.cpp:(.bss+0x0): multiple definition of 'a'
ccOSsV4n.o:a.cpp:(.bss+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

我真的很困惑。 C和C++中的全局变量有区别吗?

最佳答案

以下是标准的相关部分。请参阅标准文本下方的说明:

§6.9.2/2 外部对象定义

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

ISO C99 §6.9/5 外部定义

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

在 C 版本中,“g”全局变量被“合并”为一个,因此最终您将只有一个被声明两次。这没关系,因为当时不需要 extern,或者可能没有退出。因此,这是出于历史和兼容性原因构建旧代码。这是此旧功能的 gcc 扩展

它基本上让 gcc 为名为“a”的变量分配内存,因此可以有多个声明,但只有一个定义。这就是为什么下面的代码即使使用 gcc 也无法工作的原因。

这也称为暂定定义。 C++ 没有这样的东西,那就是在它编译的时候。 C++没有临时声明的概念。

A tentative definition is any external data declaration that has no storage class specifier and no initializer. A tentative definition becomes a full definition if the end of the translation unit is reached and no definition has appeared with an initializer for the identifier. In this situation, the compiler reserves uninitialized space for the object defined.

但是请注意,即使使用 gcc,以下代码也无法编译,因为这不再是带有赋值的暂定定义/声明:

在文件“a.c/a.cpp”中

int a = 1;

在文件“b.c/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

关于c++ - C和C++中的全局变量有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18544249/

相关文章:

c - 迭代链表,if 语句不起作用

linux - 制作 : *** [install] Error 1

c - 为什么在启用 GCC 优化的情况下,这段代码使用 strlen 的速度要慢 6.5 倍?

c++ - 不显示逻辑盘符

c++ - 将文本文件输出组织到列中

c - 需要帮助修复在文本文件中查找 max_min_numbers 的函数

c - 该程序编译但在执行时终止。为什么?

c++ - 错误地将字符串传递给 printf 样式日志函数时丢失错误

c++ - 创建链接到另一个 dll 的 dll (MSVS2008 C++)

c - 尝试使用 c 反转字符串