c++ - 头文件中的 C 与 C++ 全局变量

标签 c++ c global-variables language-lawyer cross-language

我知道全局变量不应该在 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.hlib.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/

相关文章:

hadoop - Apache Pig中的DEFINE语句

c++ - 如何为 YAML::Emitter 重载 << 运算符以序列化包含另一个自定义类的 vector 的自定义类

c++ - OpenGL 正在泄漏内存。哪个对象没有被释放?

我可以用吗 。作为 gnu c 结构中的成员限定符

c++ - sizeof(* struct pointer) 是否给你结构的值

objective-c - Objective-C 中的全局变量 - extern 和 .m 文件声明顶部的差异

c++ - 这段代码是如何工作的,反转字符串的真正简短方法,它有效,但我不知道如何

c++ - 字符串与最相似的字符串比较

java - 解释参数的方法

python - 收集类变量中的所有实例总是不好的吗?