首页
作者: Dai Yuwen
我看到有些程序员用C语言写程序的时候,不太了解头文件的作用。他们对编 译器提出的警告不在乎,仅以编译、连接通过为目标,这可能会有潜在的危害。
假设我们写了一个很简单的程序: main调用了一个函数foo:
#include <stdlib.h> #include <stdio.h> int main(void) { int i; i = foo (2, 3); printf ("foo returns %d\n", i); exit(0); } int foo (int a) { return (a+a); }此程序有严重的错误,但是如果我们用命令
$ gcc -c main.c编译的时候,没有任何警告或出错信息。好,我们加上-Wall选项:
$ gcc -c -Wall main.c main.c: In function `main': main.c:8: warning: implicit declaration of function `foo'这句implicit declaration of function可能是被程序员忽 视最多的警告了。 好,我们继续忽视它,接下来连接也能通过:
$ gcc -o ex1 main.o运行也没有问题。 但你不觉得毛骨悚然吗? 一个严重的错误就这样从你眼 皮底下过去了。你的程序越来越复杂,这个警告混在一大堆编译信息里,根本就 注意不到了。 直到某一天一些奇怪的问题出现了,你开始调用各种土枪洋炮来调试 程序…
其实,如果我们稍微尊重些编译器,把函数的声明加在main的前面,问题错误马上显现:
int foo (int a); int main(void)编译
$ gcc -c -Wall main.c main.c: In function `main': main.c:9: error: too many arguments to function `foo'
这就是函数声明的作用。 它既告诉程序员如何调用一个函数,也让编译器检 查调用与函数原型是否一致。 有些人以为连接器会检查参数匹配的问题,连接 不出错就万事大吉了,这是不对的。你想,参数是以寄存器或压栈的方式传递的。 编译之后,参数类型和个数等信息都已丢失,连接器还能帮你查错吗? 它只是 简单地把名字相同的符号连接起来而已。