我刚刚开始学习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.o
和sum.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/