我无法将头和标题后卫围绕。我已经阅读了其他问题及其答案,但我仍然无法在Visual Studio 2013中完成这项工作:
main.cpp
#include "stdafx.h"
#include <iostream>
#include "add.h"
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}
add.cpp
#include "stdafx.h" //ADDED LATER; NOW WORKING (AND SEE QUESTION 2 BELOW)
#include "add.h" //ADDED LATER; NOR WORKING (AND SEE QUESTION 2 BELOW)
int add(int x, int y) {
return x + y;
}
add.h
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
当我编译时,控制台窗口在屏幕上闪烁,然后消失。错误列表包含:
错误1错误lnk2019:未解决的外部符号" int __cdecl 添加(int,int)"(?添加@@ yahhh@z)在功能中引用 _wmain C: User Danny Dancy Documents Visual Studio 2013 Projects Addad Program Main Main Main.obj Main
错误2错误LNK1120:1未解决 外部C: Users Danny Documents Visual Studio 2013 projects Adad Program debug main.exe main
1。标题和标头警卫如何工作?我知道如何通过#add.h
,它使main.cpp
意识到add(int x, int y)
的声明,但是如何找到其定义?
2。我的代码中有什么错?
我的代码正在编译。我的代码之所以没有编译的原因是因为我一直在 file> new> file ... 将文件添加到我的项目中,而不是通过 source Files 和标题文件 Solution Explorer 的部分在Visual Studio中。我还需要将 #include "stdafx.h
添加到add.cpp文件。
以这种方式考虑:预处理每个.cpp
文件,然后与其他文件完全分开。
所以让我们首先预处理main.cpp
。这涉及查看以#
开头的所有行。文件main.cpp
仅具有#include
行,只需复制其包括的文件内容即可。我将用评论来代表stdafx.h
和iostream
的内容,但实际上我会复制add.h
的内容:
// Contents of stdafx.h
// Contents of iostream
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}
现在看到add.h
的内容已将其带入main.cpp
中?碰巧的是,这带来了一些更多的预处理指令,因此我们需要做他们说的事情。第一个检查是否尚未定义ADD_H
(在此文件中),这不是,因此将所有内容都放在#endif
:
// Contents of stdafx.h
// Contents of iostream
#define ADD_H
int add(int x, int y);
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}
现在剩余的预处理器指令定义了ADD_H
,我们将剩下的最终翻译单元:
// Contents of stdafx.h
// Contents of iostream
int add(int x, int y);
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}
现在可以编译此文件。如果您调用add
之类的函数,则编译器只需要能够看到该功能的声明即可成功编译。预计该函数将在某些其他翻译单元中定义。
现在,让我们看一下预处理add.cpp
。实际上,add.cpp
没有任何预处理指令,因此无需发生任何事情。通常,您将#include "add.h"
,但是如果您不这样做,您的程序仍将编译。因此,在预处理后,我们仍然有:
int add(int x, int y) {
return x + y;
}
然后进行编译,我们现在有一个add
函数的定义。
所有.cpp
文件都已编译后,然后将其链接。链接器负责查看编译的main.cpp
使用该函数add
,因此可以查看其定义。它在编译的add.cpp
中找到了定义,并将它们链接在一起。
您可能会想知道为什么我们根本可以包括后卫。在此示例中,它似乎一文不值。没错,在此示例中,它实际上没有任何用途。在那里包括后卫,以防止同一标头被包含在一个文件中。当您拥有更复杂的项目结构时,这很容易发生。但是,让我们看一个不切实际的示例,其中main.cpp
包括add.h
两次:
#include "stdafx.h"
#include <iostream>
#include "add.h"
#include "add.h"
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}
预处理给您:
// Contents of stdafx.h
// Contents of iostream
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
system("pause");
return 0;
}
第一个#ifndef
将是过程,它将看到ADD_H
尚未定义,并且在#endif
保留之前,所有内容均未定义。然后定义ADD_H
。
然后处理第二个#ifndef
,但此时已定义ADD_H
,因此所有内容都可以直到#endif
被丢弃为止。
这很重要,因为对函数(以及许多其他事情)具有多个定义会给您带来错误。
IDE依次编译每个.cpp文件以生成该特定文件的对象文件(机器代码)。
完成所有操作,它将写入位以形成可执行文件。IDE知道需要与什么联系。
这是一些简单的anwser