在C ++中使用单独的文件时,我知道可以使用这样的头文件声明函数:
// MyHeader.h
int add(int num, int num2);
// MySource.cpp
int add(int num, int num2) {
return num + num2;
}
// Main.cpp
#include "MyHeader.h"
#include <iostream>
int main() {
std::cout << add(4, 5) << std::endl;
return 0;
}
我的问题是,在这种情况下,当MyHeader.h和Main.cpp根本没有对MySource.cpp的引用时,编译器如何确定add(int,int)的函数定义?
因为,如果程序中有多个添加函数(具有相同的参数),我如何确保在某种情况下使用正确的函数?
答案 0 :(得分:3)
函数声明为编译器提供了足够的信息来生成对该函数的调用。
然后,编译器生成一个目标文件,该文件指定该目标文件所引用的外部函数的名称(在C ++的情况下被修改以指定参数,名称空间,cv限定符等)(以及另一个名称列表)。
然后,链接器获取所有这些目标文件,并尝试匹配某些内容所引用的名称,但不会定义与定义相同名称的其他目标文件。然后它分配并填写地址,因此当一个目标文件引用nameX时,它会填充从另一个文件分配给nameX的地址。
至少在典型情况下,它查看的目标文件将包含许多库(标准库+您指定的任何其他库)。库基本上只是一个对象文件的集合,一起塞进一个文件中,有足够的数据来索引哪些数据是哪个目标文件。在少数情况下,它还包括一些额外的元数据(例如)快速找到定义特定名称的目标文件(为了更快的链接,显然很方便,但实际上并非绝对必要)。
如果有两个或多个函数具有完全相同的错位名称,那么您的代码具有未定义的行为(您违反了一个定义规则)。链接器将通常给出一条错误消息,告诉您nameZ在目标文件A和目标文件B中都已定义(但C ++标准并不真正需要)。
答案 1 :(得分:2)
编译器不会“确定”(您的意思是“知道”)函数定义。 链接器可以。您刚刚发现了构建过程包含编译和链接的原因。
因此,基本上,编译器在这里生成两个目标文件。一个包含add
的定义,另一个包含“未知”函数add
。然后,链接器获取两个目标文件并将引用和定义放在一起。当然,这只是一个非常简单的解释,但对于初学者来说,这就是你需要知道的全部。
答案 2 :(得分:0)
编译器不编译头文件;它编译源文件。当标题在正在编译的源文件中包含#included时,它将在头文件中包含代码,但是就其自身而言,头文件不会做&#34;做&#34;任何东西。
此外,编译器并不担心是否定义了函数。它只是编译函数声明。它是解析函数定义的链接器。
根本不需要包含函数的定义,除非您需要链接的其他代码调用它。
关于你的问题,&#34;如果程序中有多个添加函数(具有相同的参数),我怎样才能确保在某种情况下使用正确的函数?&#34;:它取决于链接器和设置,但通常,如果您具有多个具有相同签名的函数定义,链接器将发出错误,指出函数是多重定义的。