我今天写了一个简单的示例,只是想看看它是否可以编译,当我发现它可以编译时,我实际上感到非常惊讶!
这是示例:
你好
#ifndef HELLO_H
#define HELLO_H
// Function prototype
void say_hello();
#endif
你好
注意:这不包括“ hello.h”,就像在我永远的历史中见过的每个C ++示例一样!
// #include "hello.h" <-- Commented out. The corresponding header is NOT included.
#include <iostream>
void say_hello() {
std::cout << "Hello!" << std::endl;
}
main.cpp
#include "hello.h"
int main() {
say_hello();
}
然后,我将“ hello.cpp”编译为静态库,如下所示:
g++ -c hello.cpp
ar -rvs libhello.a hello.o
然后,我编译了“主”应用程序并将其链接到库
g++ -o main main.cpp -L. -lhello
并运行它,它执行得很好!
./main
你好!
当我感到惊讶的时候...我确实理解为什么这样做。这是因为“ hello.cpp”中的函数未声明为静态,因此具有外部链接并且可以从外部看到。将其设置为静态将由于未定义引用而导致链接失败。
因此,这里有一个问题……如果这行得通,那么为什么每个地方的人总是在“ .cpp”实现文件中包括“ .h”头文件和函数声明。显然,如果仅定义自由函数,则没有必要,并且如果不包含头文件,一切都会很好。
那么为什么我们总是包含它呢?-是否只是对链接器的工作原理普遍缺乏了解?还是还有更多?
让我们更改您的hello.cpp
:
// #include "hello.h" <-- Commented out. The corresponding header is NOT included.
#include <iostream>
int say_hello() {
std::cout << "Hello!" << std::endl;
return 0;
}
这将与以前的版本一样编译。它也可能会链接-但不正确。返回类型错误。
这是未定义的行为,但是在许多常见的实现中,您将不使用它,因为您不使用返回值,并且通常在寄存器中将其返回。但是,不必一定如此-您在运行时可能会遇到非常奇怪的错误。特别是如果差异稍微复杂一些(如double
调用者期望时返回int
-通常会在不同的寄存器中返回)。
另一方面,如果您写了:
#include "hello.h"
#include <iostream>
int say_hello() {
std::cout << "Hello!" << std::endl;
return 0;
}
然后,头文件中的声明将与CPP文件中的定义不匹配-并且您将获得一个不错的,易于理解的编译器错误消息。
实际上,这是一个好主意,如果您没有外部函数的声明,GCC会抱怨。(如果您在命令行中使用-wall -werror,它将停止您的构建。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句