泰晓科技 -- 聚焦嵌入式 Linux - 追本溯源,见微知著!
网站地址:http://tinylab.org
微信公众号关注我们新浪微博


扫一扫

关注 @泰晓科技
赞助泰晓原创 ○ 在线实验Linux ○ 下载开源书籍
请稍侯

[c-faq] 1.25-隐式函数声明

Wen Pingbo 创作于 2013/08/26

by PingboWen of TinyLab.org 2013/08/24

在 C 语言中,隐式函数声明是指函数在调用之前没有明确的声明或定义。 不同的编译器对待隐式函数声明的方式不同。在 GCC 中,编译器只会给出一个警告,但是只要不和默认函数原型冲突,编译器是不会报错的。 下面来看一个实验:

test.c:

#include <stdio.h>

int f1()
{
	return f2();
}

int f2(int i)
{
	return 1;
}

int main(int argc, char * argv[])
{
	printf("%d\n",f1());
	return 0;
}

当你直接用 gcc test.c 的方式编译这个程序的时候,编译器是不会报错的,并且能够正常通过编译。

但是当你把上面的 f2 函数的返回类型改为 char 后,还是按照原先的方式编译(gcc test.c),你会发现,编译器会报错,提示在 f2 定义的那个地方和函数 f2 类型冲突。

怎么会出现类型冲突的错误?我之前有定义 f2 么?

其实这中间就是隐式函数声明在捣鬼。在 gcc 中,如果编译器碰到一个未声明的函数调用,编译器默认会把这个函数的原型当作 int f()。也就是说这个函数可以接受任意的参数,并且返回一个整型数。这也是为什么第一次编译的时候,编译器是可以通过编译的,并且程序运行正常。因为下面的 f2 定义刚好和默认的函数原型兼容。

但是,如果我们把返回类型换成 char 之后,这就和前面的函数原型不兼容了。就相当于同一个文件中出现两个对同一个名字的不同的函数声明,这在 C 语言中,当然是不允许的,所以编译器会报错:类型冲突。

在 C89 的规范中,是允许这种隐式函数声明,且 gcc 默认是按照 c89 的标准来编译程序的,这也是为什么 gcc 在第一次编译的时候,连一个警告都不出,其实你可以加一个 -Wall 的参数, gcc 就会出现警告:隐式函数声明。

在 C99 的规范,已经不允许隐式函数声明了。所以如果你在用 gcc 编译的时候,加上 -std=c99 的时候,编译器马上会出现一个警告:隐式函数声明。如果你再加上一个 -Werror 的选项的话,那就直接出现错误了。

从这也可以看出,不同的标准之间的差异。以后编译程序的时候,还是尽量加上 -Wall -std=c99 ,可以发现很多隐藏的错误。

Read More: