【问题标题】:When to use extern in C++何时在 C++ 中使用 extern
【发布时间】:2012-05-12 09:59:41
【问题描述】:

我正在阅读“Think in C++”,它刚刚介绍了extern 声明。例如:

extern int x;
extern float y;

我想我理解它的含义(没有定义的声明),但我想知道它什么时候证明有用。

有人可以举个例子吗?

【问题讨论】:

  • 我不得不多次使用extern 提供定义。当仅定义另一个源文件中的表时,Microsoft 工具会因缺少符号而产生链接错误。问题是,该表是const,而C++ 编译器在翻译单元中将其提升为static。例如,请参阅 ariatab.cppkalynatab.cpp
  • 我认为 Nik 的答案是正确的,因为他是唯一一个似乎回答了 C++ 问题的人。其他人似乎都跑题了。
  • 从 C++17 开始,inline 可能是完成您想要使用 extern 完成的任务的更好方法。使用inline,您可以在标头中定义全局变量,而不必担心多个定义问题。 stackoverflow.com/questions/38043442/…

标签: c++ variable-declaration


【解决方案1】:

当您有全局变量时,这很有用。您在标头中声明全局变量的存在,以便包含该标头的每个源文件都知道它,但您只需要在您的一个源文件中“定义”一次。 p>

为了澄清,使用extern int x; 告诉编译器存在一个名为xint 类型的对象某处。知道它存在于哪里不是编译器的工作,它只需要知道类型和名称,这样它就知道如何使用它。编译完所有源文件后,链接器会将x 的所有引用解析为它在已编译源文件之一中找到的一个定义。要使其工作,x 变量的定义需要具有所谓的“外部链接”,这基本上意味着它需要在函数之外(通常称为“文件范围”)声明,并且没有static关键字。

标题:

#ifndef HEADER_H
#define HEADER_H

// any source file that includes this will be able to use "global_x"
extern int global_x;

void print_global_x();

#endif

来源 1:

#include "header.h"

// since global_x still needs to be defined somewhere,
// we define it (for example) in this source file
int global_x;

int main()
{
    //set global_x here:
    global_x = 5;

    print_global_x();
}

来源 2:

#include <iostream>
#include "header.h"

void print_global_x()
{
    //print global_x here:
    std::cout << global_x << std::endl;
}

【讨论】:

  • 谢谢。那么,如果我在没有 extern 关键字的头文件中声明了一个全局变量,那么包含头文件的源文件就看不到它了吗?
  • 你不应该在头文件中声明全局变量,因为当两个文件包含相同的头文件时,它不会链接(链接器会发出关于“重复符号”的错误)
  • @Aslan986:不,更糟糕的事情发生了。每个包含头文件的源文件都有它自己的变量,因此每个源文件都将独立编译,但链接器会报错,因为两个源文件将具有相同的全局标识符。
  • 当你不使用“extern”这个词时,那么现在变量就存在了。当您使用“extern”时,它是“嘿,其他地方有这个变量”。很抱歉没有回答它是定义还是声明,因为我总是对这两个感到困惑。
  • @CCJ:包含防护仅适用于包含它的源文件。它会阻止在同一个源文件中包含两次相同的标头(以防其他标头也包含它等)。所以即使有包含守卫,每个包含头文件的源文件仍然有自己的定义。
【解决方案2】:

当您在几个模块之间共享一个变量时,它很有用。您在一个模块中定义它,并在其他模块中使用 extern。

例如:

在file1.cpp中:

int global_int = 1;

在file2.cpp中:

extern int global_int;
//in some function
cout << "global_int = " << global_int;

【讨论】:

  • 这个答案比公认的答案更正确,因为它不使用头文件,并且明确指出它仅在少数模块之间共享时有用。对于较大的应用程序,最好使用例如 ConfigManager 类。
  • 在涉及命名空间时是否有任何问题,global_int 在全局命名空间中,如果我要在某些命名空间部分的 file2.cpp 中使用它,我必须正确地确定它的范围?即namespace XYZ{ void foo(){ ::global_int++ } };
  • @Zac:另一方面,由于不在标头中声明全局变量,您无意中使确定它的实际定义位置变得更加困难。通常,如果您看到在abc.h 中声明的全局变量,则很有可能它会在abc.cpp 中定义。一个好的 IDE 总是有帮助的,但组织良好的代码总是一个更好的解决方案。
  • file2.cpp中没有extern,在include之后仍然可以访问global_int。为什么我需要它?
  • @TomSawyer 您不想在这种情况下包括在内。 file1.cpp 和 file2.cpp 应该是不同的编译单元。包含 .cpp 文件是非常罕见的做法。
【解决方案3】:

这一切都与链接有关。

前面的答案很好地解释了extern

但我想补充一点。

您在 C++ 中询问 extern,而不是在 C 中,我不知道为什么没有答案提到 extern 带有 @ 的情况C++ 中的 987654324@。

在 C++ 中,const 变量默认具有内部链接(不像 C)。

所以这种情况会导致链接错误

来源 1:

const int global = 255; //wrong way to make a definition of global const variable in C++

来源 2:

extern const int global; //declaration

应该是这样的:

来源 1:

extern const int global = 255; //a definition of global const variable in C++

来源 2:

extern const int global; //declaration

【讨论】:

  • 为什么它在 c++ 中工作时在定义部分不包含“extern”是错误的?
  • 我似乎没有在 VIsual Studio 和 Visual Micro 中遇到链接错误。我错过了什么?
  • @lartist93 @Craig.Feied 我相信您可能需要再次仔细检查。即使编译器没有通知链接错误,如果没有extern 的定义,您是否可以检查两个源中的两个对象是否相同?您可以通过在源代码 2 中打印出 global 的值来做到这一点。
  • 确认,如果在const int global = 255; 中省略extern,则在MSVS 2018 中存在链接错误。
  • 我已经看到extern 用在 C++ 服务器代码中,其中客户端是用 C 编写的。我一直认为这样做是为了将 C++ 函数公开给 C,否则将无法链接给它。这是正确的吗?
【解决方案4】:

当您想要一个全局变量时,这很有用。您在某个源文件中定义全局变量,并在头文件中将它们声明为 extern,这样任何包含该头文件的文件都将看到相同的全局变量。

【讨论】:

  • 无论如何这听起来不太OOP,我会将它们放入一个单例类...或返回本地静态值的函数...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 2019-12-22
  • 2020-08-11
  • 1970-01-01
相关资源
最近更新 更多