我知道全局变量不应该在 header 中定义,我们应该使用 extern
仅在 header 中声明它们。
但我仍然尝试在以下 header 中定义全局变量 lib.h
强>:
//lib.h
int i;
void add();
尝试在 C 和 C++ 中使用此 header 时,我得到了一些有趣的结果
在 C 中,我将 header 包含在 main.c
中并在 lib.c
,并且它编译并运行得很好:
//main.c
#include <stdio.h>
#include <stdlib.h>
#include "lib.h"
int main()
{
printf("%d\n", i);
add();
printf("%d\n", i);
return 0;
}
----
//lib.c
#include "lib.h"
void add(){
i++;
}
但是当我使用类似的代码在 C++ 中运行它时( lib.h
和 lib.cpp
与上面相同),它给出了有关 i
的错误消息具有多个定义的变量:
//main.cpp
#include <iostream>
#include "lib.h"
using namespace std;
int main()
{
cout<<i<<endl;
add();
cout<<i<<endl;
return 0;
}
为什么它用 C 编译而不是用 C++ 编译?
最佳答案
这种行为差异并非巧合,也不是编译器中的错误。这是 C 和 C++ 标准的严格应用,它们在全局范围内拥有多个 int i;
的含义上存在分歧。
在 C++ 中是无效的
在 C++ 中,int i;
是(未初始化的)对象的定义。 One Definition Rule (ODR) 不允许您多次定义同一个全局变量。
这是在 C++ 标准的 [basic.def.odr] 部分中定义的
在 C 语言中是有效的
在 C 语言中,int i;
是一个暂定定义。对完全相同的全局变量进行多次临时声明是完全有效的。
这是在 C11 标准第 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.
请注意,该子句的措辞方式并未提及在多个翻译单元中定义同一变量的情况。上面标准引用的最后一句并不意味着它在每个文件中都是不同的变量(为此,您需要使用 static
进行内部链接)。它只是说该行为就好像变量的初始值为 0。
这种中立是有原因的:
该标准将这种情况识别为未定义的行为:
Annex J.2: An identifier with external linkage is used, but in the program there does not exist exactly one external definition for the identifier, or the identifier is not used and there exist multiple external definitions for the identifier
但该标准还将具有多个定义的情况标识为广泛支持的通用扩展,只要这些定义不相互矛盾即可:
Annex J.5.11: There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword
extern
; if the definitions disagree, or more than one is initialized, the behavior is undefined
重要建议
因此,如果您打算编写可移植代码,我强烈建议您在 header 中使用 extern
并在一个且仅一个编译单元中定义该值。这是安全、清晰、明确的,并且适用于 C 和 C++。
关于c++ - 头文件中的 C 与 C++ 全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55404143/