C语言隐式声明与GCC内建函数
什么是C语言的隐式声明
在C语言中,函数在调用前不一定非要声明。如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码。下面是一个例子:
#include <stdio.h>
int main() {
double x = no_declare_func();
return 0;
}
$ gcc -c implicitDeclare2.c
$ gcc implicitDeclare2.o -o implicitDeclare2
implicitDeclare2.o: In function `main':
implicitDeclare2.c:(.text+0xe): undefined reference to `no_declare_func'
collect2: error: ld returned 1 exit status
可以看到上面的代码没有定义no_declare_func,但是gcc在编译的时候并不会报错,因为C语言规定,对于没有声明的函数,自动使用隐式声明,也就变成如下代码(函数的隐式声明默认为int型):
#include <stdio.h>
int no_declare_func();
int main() {
double x = no_declare_func();
return 0;
}
在链接的时候会报错,因为链接过程中没有找到函数no_declare_func的定义。
目前C++是没有隐式声明这一说,遇到这种没有函数声明的情况,会直接报error。
GCC内建函数
内建函数(built-in),即一个系统或者工具提供的默认就能用的函数,我的理解是默认情况下,gcc在链接的时候如果没有找到定义,就会自动去链接库中对应名称的函数,gcc的内建函数大多是为了对代码进行优化。
gcc内建函数相关的选项如下:
-fbuiltin:
gcc编译默认选项,默认通过名字来识别内建函数-fno-builtin:
禁用GCC编译器内建函数。如果在gcc编译时用了-fno-builtin选项,则除非利用前缀__builtin_进行引用,否则不识别所有内建函数。例如,为了获得内建strcpy函数,应该调用__builtin_strcpy()而不是名为 strcpy() 的函数。-fno-builtin-xxx:
gcc编译时想特定的不使用某些函数的内建函数,例如,想使用除sqrt()之外的所有内建函数,则可以添加此选项-fno-builtin-sqrt
隐式声明带来的灾难
不要用隐式声明!!!不要用隐式声明!!!不要用隐式声明!!!
- 首先,隐式声明是默认int型,如果没有对应同名的内建函数,编译不报错,链接报错,这种情况上面已经介绍
- 有同名的内建函数,且类型相同,gcc编译链接没问题
- 有同名的内建函数,类型不同,链接报warning“隐式声明与内建函数不兼容”,但是以内建函数的函数原型为准。gcc编译器在编译时能够自动在常用库头文件(内建函数)中查找与隐式声明同名的函数,如果发现两者并不相同,则会按照内建函数的声明原型去生成调用代码。
case 2:
#include <stdio.h>
int main(){
int x = abs(-1,2,3,4,5);
printf("%d \n", x);
return 0;
}
其中,abs的隐式声明函数原型为:
int abs(int);
abs()内建函数原型为:
int abs(int);
gcc编译链接均没有报错,执行结果如下:
$ gcc -c implicitDeclare.c
$ gcc implicitDeclare.o -o implicitDeclare
$ ./implicitDeclare
1
可见,gcc的内建函数机制并不关心函数的参数,只是关心函数的返回值。虽然这个例子的运行结果都是正确的,但是这种正确是“碰巧”的,因为额外的函数参数并没有影响到结果。这种偶然正确是程序中要避免的。
case 3:
#include <stdio.h>
int main(){
double x = sqrt(1);
printf("%lf \n", x);
return 0;
}
其中,sqrt()的隐式声明函数原型为:
int sqrt(int);
sqrt()的内建函数原型为:
double sqrt(double);
编译报警告,链接按照内建函数原型链接:
$ gcc -c implicitDeclare.c
implicitDeclare.c: In function ‘main’:
implicitDeclare.c:4:16: warning: incompatible implicit declaration of built-in function ‘sqrt’ [enabled by default]
double x = sqrt(1);
^
$ gcc implicitDeclare.o -o implicitDeclare
但是仍然可以执行,结果如下:
$ ./implicitDeclare
1.000000