2

我有 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 时,它给出了错误“未定义的对‘key’的引用”。请帮助我在此代码中找到问题。

4

6 回答 6

9

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

// 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

第一个编译(但不链接)ac 第二个对 bc 执行相同的操作 第三个实际上将两者链接在一起并生成一个可以执行的二进制映像(传统上命名为a.out,但例如在 Windows 上通常更改为a.exe)。

于 2010-05-24T17:26:27.563 回答
3

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

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

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

于 2010-05-24T17:30:40.767 回答
2

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

于 2010-05-24T17:33:07.130 回答
2

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

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

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

于 2010-05-24T17:36:59.710 回答
1

我猜你得到一个链接错误?链接 b 时需要包含 ao,但如果 a 和 b 中确实有“main”,那将不起作用。您需要制作声明密钥的 c.cpp,并将 co 链接到 a.exe 和 b.exe。

于 2010-05-24T17:30:29.100 回答
0

两者a.cppb.cppmain()定义了函数,并且您只能为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

(第一行)的-c选项说“只编译,不链接”。链接步骤确定是否定义了所有变量,并且它们在您 compile 时未定义,但它们在您编译时定义(第二行)。gccb.cppa.cpp

于 2010-05-24T17:53:17.923 回答