假设我有3个文件:add.h,add.cpp和main.cpp。这是C ++培训站点上的一个常见示例,其中add.h包含名为“add”的函数的原型。 Add.cpp包含原型的声明,main.cpp包含add.h,然后调用add()函数将两个数字(x和y)一起添加。
我的问题是:无论我将add.cpp命名为什么,我的程序都运行得很好。 Elephant.cpp与doctorWhoRules.cpp一样有效。编译器是否搜索所有本地.cpp文件以在add.h中查找给定的原型?我没有在任何地方声明包含它的.cpp文件的名称。我只是对这是如何工作感到困惑。
谢谢!
答案 0 :(得分:2)
我认为您正在混合Java
和C++
。在Java(像Eclipse这样的编辑器)中,存在一个通用限制,即您的class
名称应与文件名相同。即。
// Add.java
class Add
{
}
在C ++中没有这样的限制。您的文件名可以是任何有意义的名称。您唯一需要注意的是您的实施文件包含.cpp
/ .cxx
/ .C
等扩展名(我不知道现代编译器是否支持除此之外)
即使你的头文件也可以是除.cpp
以外的任何其他任意扩展名;头文件的更常规扩展是.h
,.hpp
等。
答案 1 :(得分:2)
名称是惯例。你可以任意命名,包括“weekly.newsletter”。您不必使用“add.cpp”。
也就是说,遵循惯例是明智的,除非你有理由不这样做,而且有些工具会使用扩展来推断使用的语言。
例如,当人们使用“foo.cpp”文件时,非常会让人感到困惑,就好像它们是头文件一样!然而,这在C ++中是允许的。然而,它违反惯例,编程很难实现。
答案 2 :(得分:1)
请参阅上面的文件名解答。链接器收集目标文件,匹配代码等并构建可执行文件。
答案 3 :(得分:1)
不同的可能性;
1)你实际上并没有重命名文件,你只是用一个新名称保存文件 - 而旧的add.cpp仍然存在并且仍然有效。
2)有一个旧的add.obj,它正在被链接
3)文件作为项目打开,visual-studio发现打开的文件实际上是你要编译成的文件和exe
答案 4 :(得分:1)
是的,编译器会搜索所有文件。更确切地说,它执行一次传递(“编译”),将代码减少到机器指令,并向每个文件添加它全局定义的符号列表(函数和变量名称),然后是第二次传递(“链接”,技术上不是完全匹配这些名称的部分编译器。
.h文件中原型的要点只是让编译器在编译main.cpp时可以使用add.cpp中实际定义的确切类型和名称(或者你称之为的任何内容)。这使得可以在不实际看到实现文件的情况下进行编译部分。
模板打破了这个“单独的编译”模型,因为编译器需要在编译期间看到模板的整个定义,因为它必须根据模板的方式生成特定于类的代码叫做。通常,模板放在.h文件中并包含在任何地方。
答案 5 :(得分:0)
假设我们有add.h add.cpp和main.cpp。
你需要main.cpp和add.cpp中的add原型。 main.cpp需要它,因为它想要使用类add和add.cpp需要它,因为它想要实现它,因此需要它的原型。如您所知,通过包含头文件来完成此操作。 在add.cpp和main.cpp中执行#include“add.h”。
现在编译器开始行动创建两个目标文件,即main.o和add.o.所以仍然主要只知道添加,内部机制(实现)仍然不存在。之后,链接器将main.o和add.o组合成一个可执行文件,其中包含运行从main添加的所有铃声和口哨声。
编译后,每个目标文件都按名称知道。在链接之后,他们实际上知道如何通过名称来调用它们(他(实现)所在的地方。
在编译器之前,我们有另一个称为预处理的步骤。在此步骤中完成的一件事是复制#include之后的文件内容。
无论你如何调用add.h都没关系,但你必须在main.cpp和add.cpp中包含正确的文件。无论你如何调用add.cpp或main.cpp,都只需要指示你的编译器如何调用它们。例如,在visual studio中,这是通过在项目文件中重命名它们自动完成的。如果使用gcc,您必须自己指导编译器和链接器。在这种特定情况下,您可以执行以下操作。
将add.cpp编译成add.o:
gcc -c add.cpp
将main.cpp编译为main.cpp:
gcc -c main.cpp
将add.o和main.o链接到myniceprogram:
gcc -o myniceprogram add.o main.o