【发布时间】:2018-05-23 19:38:53
【问题描述】:
我有两个文件:test1.c 和 test2.c,其中包含 main() 函数。
test1.c:
#include <stdio.h> // printf() function declaration/prototype
// function definition
void say_hello() {
printf("\tHello, world!\n");
}
test2.c:
#include <stdio.h> // printf() function declaration/prototype
int main() {
printf("Inside main()\n");
say_hello();
return 0;
}
这是我的makefile:
a.out: test1.o test2.o
$(CXX) -o a.out test1.o test2.o
test1.o: test1.c
$(CXX) -c test1.c
test2.o: test2.c
$(CXX) -c test2.c
现在应该清楚问题出在哪里了:test2.c 中的 main() 函数调用 say_hello() 却没有声明它!
我运行以下命令,以使用 gcc 编译器:
make CXX=gcc
我在屏幕上收到此警告:
gcc -c test1.c
gcc -c test2.c
test2.c: In function ‘main’:
test2.c:16:3: warning: implicit declaration of function ‘say_hello’ [-Wimplicit-function-declaration]
say_hello();
^
gcc -o a.out test1.o test2.o
虽然 *.o 文件已编译并链接到可执行文件中。这很奇怪。想象一下当我运行 a.out 文件时我的惊讶,我看到 main() 成功调用了 say_hello(),这是一个没有在 main 的翻译单元内声明的函数,好像根本没有问题一样!我的理由是因为say_hello() 之前没有在test2.c 中声明,所以根本不允许main() 调用它。请注意,我已将 cmets 添加到 #include <stdio.h>。这些预处理器指令包括函数声明/原型,它们将它们的范围扩展到相应的 *.c 文件中。这就是我们能够使用它们的原因。没有函数声明/原型 == 在那个翻译单元中没有作用域,或者直到现在我都这么认为。
然后我将上面的代码编译为 C++ 代码:
make CXX=g++
我在屏幕上看到这个错误:
test2.c: In function ‘int main()’:
test2.c:16:13: error: ‘say_hello’ was not declared in this scope
say_hello();
^
makefile:18: recipe for target 'test2.o' failed
make: *** [test2.o] Error 1
g++ 做它应该做的事情,并停止编译过程。但是 gcc 没有这样做!这是怎么回事?它是 C 编程语言的优势吗?是编译器的问题吗?
【问题讨论】:
-
选择一种语言。
-
这是 C 编程语言的一项优势 - 是的。 C 很天真,认为程序员知道自己在做什么。
-
@Galaxy 声明或多或少只是告诉您某物具有什么类型(C 和 C++ 中的函数类型通常称为签名)。它实际上与多个翻译单元没有任何关系,尽管它对此也很有用。
-
@Galaxy 这个问题与这两种语言无关,因为 C++ 不允许这样做。 ;-)
-
这是一个向后兼容的东西。 C 诞生时没有原型。程序员应该知道如何调用每个函数,并且假设每个未声明的函数都返回 int (并采用未指定数量的(提升的)参数,这是没有原型的结果)。
标签: c++ c scope function-declaration