什么是C语言中的隐式函数声明?
「1、什么是C语言的隐式函数声明」
在C语言中,函数在调用前不一定非要声明。如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码。下面是一个例子:
int main(int argc, char** argv)
{double x = any_name_function();return 0;
}
单纯的编译上述源代码,并没有任何报错,只是在链接阶段因为找不到名为any_name_function的函数体而报错。
[smstong@centos192 test]$ gcc -c main.c
[smstong@centos192 test]$ gcc main.o
main.o: In function `main':
main.c:(.text 0x15): undefined reference to `any_name_function'
collect2: ld 返回 1
之所以编译不会报错,是因为C语言规定,对于没有声明的函数,自动使用隐式声明。相当于变成了如下代码:
int any_name_function();
int main(int argc, char** argv)
{double x = any_name_function();return 0;
}
「2、带来的问题」「2.1 隐式声明函数名称恰好在链接库中存在,但返回非int类型」
前面给出的例子,并不会造成太大影响,因为在链接阶段很容易发现存在的问题。然而下面这个例子则会造成莫名的运行时错误。
#include
int main(int argc, char** argv)
{double x = sqrt(1);printf("%lf", x);return 0;
}
gcc编译链接:
[smstong@centos192 test]$ gcc -c main.c
main.c: 在函数‘main’中:
main.c:6: 警告:隐式声明与内建函数‘sqrt’不兼容
[smstong@centos192 test]$ gcc main.o
运行结果:
1.000000
编译时会给出警告,提示隐式声明与内建函数’sqrt’不兼容。
gcc编译器在编译时能够自动在常用库头文件(内建函数)中查找与隐式声明同名的函数,如果发现两者并不相同,则会按照内建函数的声明原型去生成调用代码。
这往往也是程序员预期的想法。上面的例子中隐式声明的函数原型为:
int sqrt(int);
而对应的同名内建函数原型为:
double sqrt(double);
最终编译器按照内建函数原型进行了编译,达到了预期效果。然而gcc编译器的这种行为并不是C语言的规范,并不是所有的编译器实现都有这样的功能。同样的源码在VC 2015下编译运行的结果却是:
VC 编译:
warning C4013: “sqrt”未定义;假设外部返回 int
运行结果:
2884223.000000
显然,VC 编译器没有没有所谓的“内建函数”,只是简单的按照隐式声明的原型,生成调用sqrt函数的代码。
由于返回类型和参数类型的不同,导致错误的函数调用方式,产生莫名奇妙的运行时错误。
对着这种情况,由于返回类型的不同,两种编译器都可以给出警告信息,至少能引起程序员的注意。而下面这种情况,则更加隐蔽。
「2.2 隐式声明函数名称恰好在链接库中存在,且返回int类型」
测试代码如下:
#include int main(int argc, char** argv)
{int x = abs(-1);printf("%d", x);return 0;
}
此时,由于隐式声明的函数原型与gcc的内建函数原型完全相同,所以gcc不会给出任何警告,结果也是正确的。而VC 则仍然会给出警告:warning C4013: “abs”未定义;假设外部返回 int。
无论如何,隐式声明的函数原型与库函数完全相同,所以链接运行都是没有问题的。
下面,稍微改动一下代码:
#include int main(int argc, char** argv)
{int x = abs(-1,2,3,4);printf("%d", x);return 0;
}
gcc下编译链接没有任何报错。
gcc编译链接:
[smstong@centos192 test]$ gcc -c main.c
[smstong@centos192 test]$ gcc main.o
可见,gcc的内建函数机制并不关心函数的参数,只是关心函数的返回值。
vc 编译链接:
warning C4013: “abs”未定义;假设外部返回 int
虽然这个例子的运行结果都是正确的,但是这种正确是“碰巧”的,因为额外的函数参数并没有影响到结果。这种偶然正确是程序中要避免的。
「3、编程中注意事项」
C语言的隐式函数声明,给程序员带来了各种困惑,给程序的稳定性带来了非常坏的影响。不知道当初C语言设计者是如何考虑这个问题的?
为了避免这种影响,强烈建议程序员重视编译器给出的关于隐式声明的警告,及时通过包含必要的头文件来消除这种警告。
对于gcc来说,前面给出的那个abs(-1,2,3,4)的特殊例子,编译器根本不会产生任何警告,只能靠程序员熟悉自己调用的每一个库函数了。
为了避免这种问题,在C语言的C99版本中,无论如何都会给出警告。如gcc使用C99编译上述代码。
gcc -std=c99编译:
[smstong@centos192 test]$ gcc -c main.c -std=c99
main.c: 在函数‘main’中:
main.c:5: 警告:隐式声明函数‘abs’
而C 则更严格,直接抛弃了隐式函数声明,对于未声明函数的调用,将直接无法通过编译。
g 编译:
[smstong@centos192 test]$ g main.c
main.c: In function ‘int main(int, char**)’:
main.c:5: 错误:‘abs’在此作用域中尚未声明
vc 编译(作为C ):
error C3861: “abs”: 找不到标识符
在函数强类型这一点上,C 确实比C更严格,更严谨。
来源:https://blog.csdn.net/smstong/
什么是C语言中的隐式函数声明?相关推荐
- 万恶之源:C语言中的隐式函数声明
1 什么是C语言的隐式函数声明 在C语言中,函数在调用前不一定非要声明.如果没有声明,那么编译器会自己主动依照一种隐式声明的规则,为调用函数的C代码产生汇编代码.以下是一个样例: int main(i ...
- 在c语言中函数的隐函,C语言中的隐式函数声明
1 什么是C语言的隐式函数声明 在C语言中,函数在调用前不一定非要声明.如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码.下面是一个例子: int main(int ...
- C语言中的隐式声明是什么,有什么危害?warning: implicit declaration of function ‘xxx’
今天编译一个代码,提示CUSTOM_LAYER里面有一个C文件函数gettimeofday()隐式声明,用man手册查了一下,需要包含头文件#include <sys/time.h> 那么 ...
- c语言 隐式声明,关于C#:隐式函数声明和链接
最近,我了解了C语言中的隐式函数声明.主要思想很明确,但在这种情况下,我对理解链接过程有些麻烦. 考虑以下代码(文件a.c): #include int main() { double someVal ...
- C语言一定要有函数声明吗,1 什么是C语言的隐式函数声明在C语言中,函数在调用前不一定非要声明。如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码。下...
1 什么是C语言的隐式函数声明 在C语言中,函数在调用前不一定非要声明.如果没有声明,那么编译器会自动按照一种隐式声明的规则,为调用函数的C代码产生汇编代码.下面是一个例子: int main(int ...
- C 编译器隐式函数声明(Implicit function declarations in C)
C 编译器隐式函数声明(Implicit function declarations in C) 引子 C 编译器隐式函数申明 警示 引子 最近在帮同事定位一个 bug,简化如下:两个 c 文件,a. ...
- scala中的隐式转换、隐式参数和隐式类
scala中的隐式转换.隐式参数和隐式类 @(SCALA)[scala] scala中的隐式转换隐式参数和隐式类 一隐式转换 1示例 2隐式转换的条件 二隐式参数 1示例 三隐式类 1示例 隐式转换是 ...
- 直播预告 | 斯坦福助理教授马腾宇:深度学习中的隐式和显式正则化
人工智能作为科技领域最具代表性的技术,日益成为国际竞争的新焦点.当下,我国正逐步开展全民智能教育普及,设置人工智能相关课程,致力于建设人工智能的人才高地. 在此背景下,中关村海华信息技术前沿研究院立足 ...
- .NET 6 中的隐式命名空间引用
.NET 6 中的隐式命名空间引用 Intro 之前写过一篇隐式命名空间引用的大概介绍,在一些小的测试项目中也有在用,一直没作为示例给大家分享,主要原因在于之前看到了一个关于隐式命名空间引用的 Git ...
最新文章
- java word openoffice_java 使用openoffice 转换文档,成.pdf,实现在线预览效果
- Nginx安装及其编译命令、详细教程
- 左神算法:二叉树的最大 / 最小深度(普通+Morris遍历进阶)(Java版)
- python中一些特殊方法的作用
- 牛客-沙漠点列【tarjan】
- Oracle数据库卸载
- 计算机编程输入与输出,计算机编程语言的发展与输入输出设备的使用
- mac上用qt调用自己生成的qt动态库,该动态库又依赖第三方库
- wince系统安装软件_精密空调安装泄漏检测系统软件的作用
- 《Oracle DBA工作笔记》第一章
- Spring Cloud Eureka(一)搭建一个注册中心
- 华为云-云容器引擎 CCE新功能发布动态
- 网络编程之 字节序和深入理解bind()函数
- 网络安全设备Bypass功能
- jQuery TagsInput
- 【STL编程】【竞赛常用】【part 2】
- 计算机专业毕业论文怎么写够字数,本科生毕业论文要求多少字
- 极简设计模式 - UML类图几种线条
- Win10 如何进入WinRE模式?
- Contains Duplicate II - LeetCode