C语言隐式函数声明带来的错误实例(当隐式声明遇到printf)
来源:互联网 发布:vc 编程 编辑:程序博客网 时间:2024/06/06 05:00
关于C语言隐式函数声明的基本问题,请参见我的博文万恶之源:C语言中的隐式函数声明。 下面是最近遇到的一个实例之一。
client_sock = accept(server_sock, (struct sockaddr*)&client_name, &client_name_len); printf("from %s:%d\n", inet_ntoa(client_name.sin_addr), client_name.sin_port);
上述代码段摘自一个网络侦听程序,功能就是打印出客户端的IP地址和端口号。出现的症状是一运行就报段错误(segment Fault)。
网上有很多文章提到了解决方式,但是却没有分析其问题产生的原因。这里我们将彻底分析其原因,并给出解决此类问题的终极方法。
1 原因分析
inet_ntoa()这个函数的调用出了问题,是万恶之源。在万恶之源:C语言中的隐式函数声明中我们说过,C语言编译器对于没有声明原型的函数,通通作为返回类型为整数的函数来处理,参数的类型则由调用的实参自动提升后确定。例如:
non_exist_function(12, 'c');
在编译时,这个没有事先声明的函数将被当作如下形式:
int non_exist_function(int,int);
注意,’c’(char)被提升为了int。
现在回到我们的代码上来。
inet_ntoa(client_name.sin_addr), client_name.sin_port)
将会被当作:
int inet_ntoa(addr_in, unsigned short);
然而实际上真正的inet_ntoa的原型定义在了
extern char *inet_ntoa (struct in_addr __in);
这样返回值本来是指针类型,却被截断成了int类型。对于32位系统来说,由于指针类型和int类型的大小都是32位,恰好不会出现截断的情况。这也是为什么上述代码在32位系统下编译运行不会出现问题的原因。
然而到了64位系统下,char*是64位,int仍然是32位,就出现了截断问题。
然而由于printf(char*, …)是个变参函数,所以调用它时,编译器不会检查可变参数的数据类型,而是按照实参类型进行准备参数入栈。相当于
printf("from %s:%d\n", 123, 8080);
这样指示符%s对应的第一个参数的类型却是int,从而导致printf()内部在通过va_arg()提取参数时产生错误,最终导致了段错误。
如果把上述代码改写为:
client_sock = accept(server_sock, (struct sockaddr*)&client_name, &client_name_len);char* s = inet_ntoa(client_name.sin_addr);printf("from %s:%d\n", s, client_name.sin_port);
编译器就会给出警告信息:
warning: initialization makes pointer from integer without a cast [enabled by default]
这样程序员就容易发现存在的隐式函数声明。
然而我们的实际代码确实非常简洁的一行代码,导致编译器不会给出警告。
* 隐式函数声明+printf()将会导致非常隐蔽的错误!*
2 终极解决方案
GCC有个开关名为: -Wimplicit-function-declaration。只要把这个开关打开就会对所有的隐式声明函数的调用发出警告。
[smstong@cf-19 ~]$ gcc -Wimplicit-function-declaration 1.c1.c: In function ‘main’:1.c:61:3: warning: implicit declaration of function ‘inet_ntoa’ [-Wimplicit-function-declaration] printf("from %s:%d\n", inet_ntoa(client_name.sin_addr), client_name.sin_port);
这种警告比错误还严重!代码一定要彻底清除这种警告。
知道了原因,解决方法异常简单,只要把包含函数原型声明的头文件包含进来就可以了。
#include <arpa/inet.h>
- C语言隐式函数声明带来的错误实例(当隐式声明遇到printf)
- c语言的隐式函数声明">1 什么是C语言的隐式函数声明
- C语言中的隐式函数声明
- C语言中的隐式函数声明
- 该死的c语言的隐式函数声明法则
- C语言的“隐式函数声明”违背了 “前置声明” 原则
- C语言的隐式声明
- 万恶之源:C语言中的隐式函数声明
- 函数的隐式声明
- C语言函数的声明
- C 隐式声明
- C隐式声明
- 警告: 隐式声明与内建函数 ‘printf’ 不兼容 解决方法(转)
- C语言函数声明
- C语言函数声明
- C语言函数声明
- C语言--函数声明
- globalmem.c:193:2: 错误:隐式声明函数‘kmalloc’ [-Werror=implicit-function-declaration]
- 繁体简体转换器 v 1.0
- AndroidStudio 百度地图在打包后失效,显示不出地图。
- Oracle 10g配置单向stream流复制,完整记录
- android studio Mac快捷键
- php文件上传设置
- C语言隐式函数声明带来的错误实例(当隐式声明遇到printf)
- NYOJ 会场安排问题
- 收获与努力同行——2015年总结
- 岁月划过生命线——考研工作篇
- JSP_005_HttpSession之概述
- linux 如何查找命令的路径
- Stream 流环境配置流程过程介绍
- 【斐波那契应用】HDOJ KK's Steel 5620
- 获取select的选择值