c++ - header 和未解析的外部符号

标签 c++

我刚刚开始学习C ++,无法理解如何使用头文件。我已经阅读并阅读了Stack Overflow上的一些现有答案,但仍然无法很好地理解。我写了这段代码,它给了我未解决的外部错误。

总和

#ifndef SUM
#define SUM

int add(int x, int y, int z);

#endif


总和

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

int add(int x, int y, int z)
{
    return x + y + z;
}


Main.cpp

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

int main()
{
    using namespace std;
    cout << "3 + 4 + 5 = " << add(3, 4, 5) << endl;
    return 0;
}


如何解决此问题,以便我的代码可以运行?

谢谢!

编辑:忘了添加,我正在使用Microsoft Visual Studio Express 2013 Windows桌面。

最佳答案

我假设您正在尝试像这样运行程序:

g++ main.cpp
./a.out


问题在于,即使您的程序可以编译,它也不会“链接”。发生的情况是链接器无法找到“ add(int,int,int)”的代码。为了解决这个问题,您需要指定编译中的所有文件。尝试这个:

g++ main.cpp sum.cpp
./a.out


在第一种情况下,尽管直接包含了sum.h文件,但是由于存在预处理程序规范要求将其导入。然后,main.cpp进行编译,但是输出不包含add函数的代码。输出只说“调用一个在这些数字上称为加号的函数”。编译器告诉链接器,当最终将其全部转换为可执行文件时,查找功能是链接器的责任。然后,当链接程序运行时,它找不到“ main.cpp”的输出所引用的任何方法“ add”。结果,它将引发错误。

在第二种情况下,两个文件都被编译(通常是.o文件),其中包含其中包含的所有代码。现在,当链接器尝试链接所有链接时,它可以轻松找到add方法,因为它具有.o文件。尝试这样做可以帮助您了解此过程的工作原理:

g++ -c main.cpp


这会将main.cpp编译为main.o文件。在目录中执行ls以查看此文件。 -c选项要求编译器跳过链接过程,仅编译源文件。然后,执行以下操作:

g++ -c sum.cpp


如果再次查看,会发现有一个名为sum.o的文件。因此,您基本上已经将文本中的代码转换为中间格式的二进制文件。到目前为止,大多数验证,类型检查,语法检查等都已执行,而main.osum.o是有效的文件,表示执行特定计算的步骤。请注意,编译步骤不需要main方法即可工作。它只是将指令从一种格式转换为另一种格式。生成可执行文件时,它是必需的,因为您当然需要知道在运行可执行文件时应执行什么操作。要获取最终的可执行文件,您只需要执行以下操作:

g++ -o myexec.out sum.o


糟糕,您在这里看到错误。它说什么? undefined reference to main。这证实了我们先前所说的链接器需要链接到“ main”函数的想法,否则运行可执行文件时它将不知道从何处开始。让我们为其提供主要功能:

g++ -o myexec.out sum.o main.o


和..你去了..它编译了。 -o开关仅告诉g++应调用输出可执行文件什么。要运行您的程序,只需执行以下操作:

./myexec.out


仅此而已...一旦您适应了这一点,便想尝试Makefiles和autotools。现实生活中的项目包含成千上万个以类似方式编译的C ++文件,但是一旦移入两位数的文件编号,将变得很难管理。因此,我们使用make之类的工具来简化此过程并使其高度可配置。希望这可以帮助您开始!

编辑#2

以为我会很快放弃对.h文件的需要。编译器一次只处理文件。因此,当它正在处理main.cpp时,遇到了名为add(4, 5, 1)的东西,它不知道add是什么。就其所知,它可能是变量int add = 10,而我会错误地使用它。编译器如何验证这一点? sum.h文件可以帮助您解决问题,并且在此过程中也对我们有帮助。 .h文件只是告诉编译器add是哪种符号。如果您尝试制作另一个名为sum2.cpp的文件,并在其中定义为add(int x, int y)而不是3变量函数,则两个文件都将编译文件,但链接仍将失败。这是因为链接器正在查找符号add(int, int, int),而链接器正在查找add(int, int)。编译器仅根据您对代码的定义来验证您的代码。

如果要从第一行中删除#include "sum.h"语句,而仅将其替换为int add(int x, int y, int z);,然后按照上面编写的所有步骤进行操作,它将仍然有效。但是,我们在单独的文件中定义它的原因是为了使更改变得更易于管理。在这种情况下,即使sum.cpp和main.cpp分别进行编译,它们也将根据相同的定义进行编译,这使我们所有人都可以检查。定义只有一个地方,它是事实的来源,可确保sum.cpp和main.cpp都同步。

关于c++ - header 和未解析的外部符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24200211/

相关文章:

具有成员初始化器语法和已删除复制构造函数的 C++ auto

c++ - 使用声明和参数转发构造函数隐式复制结构

c++ - 使用 C++ 使用 Z3 定义集合论

c++ - 默认参数匹配 std::index_sequence

c++ - 检查多种可能性是否相等的简写

c++ - 如何避免在 C++ 中自动释放?

c++ - QT C++ 错误 : undefined reference to `vtable for appprinter'

c++模板递归双链表错误gcc(但clang++接受)

c++ - 我可以合法地将成员函数指针转换为函数指针吗?

android - 在Android Studio Project中使用Tensorflow Lite C++ API的问题