我不能让我的周围头和头警卫头。 我读过其他的问题进行解答,但我还是不能让在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:(?@@添加@ YAHHH Z)无法解析的外部符号 “INT __cdecl添加(INT,INT)” 的功能_wmainÇ引用:\用户\丹尼\文件\的Visual Studio 2013 \项目\追加程序\主\ main.obj主
错误2错误LNK1120:1个无法解析的外部C:\用户\丹尼\文件\的Visual Studio 2013 \项目\追加程序\调试\ MAIN.EXE主
1.如何做头和头警卫工作? 我看到如何通过#包括add.h
,它使main.cpp
意识到的声明add(int x, int y)
,但当时它是如何找到它的定义是什么?
2.我有什么错我的代码?
我的代码现在编译。 我的代码无法编译的原因是因为我已经打算文件>新建>文件...将文件添加到我的项目,而不是通过在Visual Studio Solution Explorer中的源文件和头文件部分添加。 我还需要添加#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