【问题标题】:problem with extern variable外部变量的问题
【发布时间】:2010-05-24 17:16:36
【问题描述】:

我有 2 个 cpp 文件和一个头文件,我已将其包含在两个 cpp 文件中。是这样的:

abc.h

extern uint32_t key;

a.cpp

#include "abc.h"
uint32_t key;
int main
{
.............
}

b.cpp

#include "abc.h"

int main
{
printf("Key: %.8x\n", key);
.............
}

现在当我编译 a.cpp 时,没有错误。但是当我编译 b.cpp 它给出了错误 “未定义对‘键’的引用”。请帮我找出这段代码中的问题。

【问题讨论】:

  • 你能告诉我们你是如何编译b.cpp的吗?您是否将 a.cpp 作为构建的一部分包含在内?

标签: c++ variables extern


【解决方案1】:

要共享一个变量,你通常有这样的东西:

// A.h
extern int key;
void show();

//a.cpp
#include "a.h"

int main() { 
    key = 1;
    show();
};

// b.cpp
#include "a.h"
#include <iostream>

int key;

void show() { std::cout << "Key = " << key; }

有几点不在这里。首先,您将extern 声明放在头文件中,并将其包含在所有 使用该变量的文件中。在一个且只有一个文件中定义变量(不带extern)。只有一个文件应包含名为main 的函数。

编辑:要构建它,您自己编译每个文件,但您必须将两个文件链接在一起。例如,使用 gcc 您可以执行以下操作:

gcc -c a.c
gcc -c b.c
gcc a.o b.o

第一个编译(但不链接)a.c。第二个与 b.c 相同。第三个实际上将两者链接在一起并生成一个可以执行的二进制图像(传统上称为 a.out,但例如在 Windows 上通常更改为 a.exe)。

【讨论】:

  • 这与 OP 场景有何不同?你在 b.cpp 中定义了 key,他在 a.cpp 中定义了……他这样做的方式有什么问题?
  • 这是从两个源文件构建一个程序;看起来 OP 正在尝试构建两个程序。
  • @Mike:是的,我错过了有两个主电源的事实。我们需要教 OP 编译...
  • @Bruno:正如最初发布的那样,他显示标题仅包含在两个源文件之一中。
【解决方案2】:

问题正是错误消息所说的。 Abc.h 声明变量,但没有定义它。 a.cpp 中的行定义了它。也就是说,a.cp​​p 是变量的物理存储出现的地方。 b.cpp 中没有这样的行,因此当您尝试编译该程序时,链接器没有为该变量定义任何存储空间。

如果您在标头中省略了“extern”说明符,那么 b.cpp 会编译得很好,但 a.cpp 可能会给出关于多个定义的错误。

当您在单个程序中有多个源文件时,“extern”说明符会发挥更大的作用。在这种情况下,它们可能都包含 abc.h,但没有“extern”,每个编译的目标文件都会有自己独立的相同变量定义。链接器通常不知道该怎么做,并且可能会抱怨,尽管我认为没有必要这样做。解决方法是使用“extern”,因此每个编译的文件文件只有一个声明。然后你选择 一个 源文件来放置定义。你可能会把它放在 abc.cpp 中,因为声明在 abc.h 中。

【讨论】:

    【解决方案3】:

    头文件中的那一行是一个声明;它告诉编译器该变量存在,但不为其分配任何空间。当您从一个或多个源文件构建程序时,其中一个还必须包含一个定义

    在您的情况下,您在a.cpp 中有一个定义,因此它包含构建程序所需的一切。 b.cpp没有定义,所以链接失败。

    有两种解决方案。将定义从 a.cpp 复制到 b.cpp,或者将其移动到第三个源文件并在构建这两个程序时将其包含在源列表中。

    【讨论】:

      【解决方案4】:

      您正在编译两个独立的程序。一个不能从另一个引用变量。 extern 关键字用于从一个对象文件中引用一个符号,该符号来自一个对象文件,而另一个对象文件中的同一可执行文件被链接

      【讨论】:

        【解决方案5】:

        我猜您遇到了链接错误?您需要在链接 b 时包含 a.o,但如果您在 a 和 b 中都确实有“main”,那将无法正常工作。您需要制作声明密钥的 c.cpp,并将 c.o 链接到 a.exe 和 b.exe。

        【讨论】:

          【解决方案6】:

          a.cppb.cpp 都定义了 main() 函数,每个程序只能定义一个 main()。所以,我假设你想要做的是在两个程序之间共享一个头文件。在这种情况下,将行添加到b.cpp 以定义key 并重新编译:

          uint32_t key;
          

          这不是使用头文件的正常方式。相反,您编写函数以将key 作为参数。这样做会设置一个全局变量,这通常是不受欢迎的。

          extern 几乎总是用来设置一个全局变量(在我脑海中,我想不出任何其他使用extern 的理由)。但是,如果您想以通常使用的方式使用extern——而不考虑是否应该使用它——您可以执行以下操作:

          • 从两个文件之一中删除 main() 函数,为了回答这个问题,我们将从 b.cpp 中删除它。
          • 使用以下两行来编译和链接你的程序(假设是 gcc):

            gcc -c -o b.o b.cpp

            gcc a.cpp b.o

          gcc(第一行)的 -c 选项显示“compile only, do not link”。是链接步骤决定是否定义了所有变量,编译b.cpp时未定义,但编译a.cpp时已定义(第二行)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多