c:strerror(或 inet-尊龙官方平台

c:strerror(或 inet_ntoa) 返回值默认整型截断导致进程核心转储 core dumped

el/2024/3/25 16:48:05

c:strerror(或 inet_ntoa) 返回值默认整型截断导致进程核心转储 core dumped

测试环境:
[test1280@localhost ~]$ uname -a
linux localhost.localdomain 2.6.32-642.el6.x86_64 #1 smp tue may 10 17:27:01 utc 2016 x86_64 x86_64 x86_64 gnu/linux
错误示例:
#include 
#include int main()
{printf("sizeof(int)   = %lu\n", sizeof(int));printf("sizeof(char *)= %lu\n", sizeof(char *));errno = eagain;printf("%s\n", strerror(errno));
}

编译、链接、运行:

[test1280@localhost ~]$ gcc -o main main.c -g
[test1280@localhost ~]$ ./main
sizeof(int)   = 4
sizeof(char *)= 8
segmentation fault (core dumped)

查看 core 文件定位问题:

在这里插入图片描述

可见,在执行 printf 【参数是 strerror 返回的字符串地址】段错误。

正确示例:
#include 
#include 
#include int main()
{printf("sizeof(int)   = %lu\n", sizeof(int));printf("sizeof(char *)= %lu\n", sizeof(char *));errno = eagain;printf("%s\n", strerror(errno));
}

编译、链接、执行:

[test1280@localhost ~]$ gcc -o main main.c -g
[test1280@localhost ~]$ ./main
sizeof(int)   = 4
sizeof(char *)= 8
resource temporarily unavailable

对比两份代码,在于是否 #include 头文件。

man strerror:

在这里插入图片描述

使用 strerror 需要包含 string.h 头文件。
为何不包含会导致段错误?

对第一份错误的示例代码重新编译链接:

[test1280@localhost ~]$ gcc -o main main.c -g -wall
main.c: in function ‘main’:
main.c:10: warning: implicit declaration of function ‘strerror’
main.c:10: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
main.c:11: warning: control reaches end of non-void function

在这里插入图片描述

即在使用 gcc 编译链接生成可执行文件时打印警告信息 -wall,可见 row 10、row 11 的 warnings。

核心转储(段错误)原因:

由于没有包含 string.s 头文件,因此 gcc 无法知道 strerror 的原型(重点是其返回值类型),于是假定其返回值类型是 int

printf ("%s") 期待的参数是一个 char * 类型变量,现在传入的是 int 类型变量(strerror 被 gcc 默认 int 类型返回值)。

在当前 linux 环境下,char * 大小8字节,int 大小4字节,也就是说 strerror 返回的 char * 的8字节数据会被截断成4字节 int 值。

strerror 返回的地址已经被截断,截断后的 int 值必然是一个非法地址,通过 printf 访问非法地址,于是核心转储。

如果通过 g 来编译链接有不同吗?
[test1280@localhost ~]$ g   -o main main.c -g -wall
main.c: in function ‘int main()’:
main.c:10: error: ‘strerror’ was not declared in this scope

直接报错无法生成可执行文件,而非警告。

猜测:

1.c中无函数重载,gcc只需依据函数名称进行函数地址映射,不查看函数返回值类型,因此能正常链接动态库的 strerror 实现并执行;

2.c 中有函数重载,g 做函数地址映射比较严格,相同的函数名称也需要依据参数类型以及顺序映射到不同的重载函数实现上;

总结:

1.执行系统调用以及库函数时要保证包含相关的头文件函数原型声明,不要缺漏,即使编译链接通过;

2.使用gcc、g 时要打开警告 -wall 开关,解决警告,可以规避潜在的问题;

3.类似的问题也存在基于 64bit 操作系统的,返回值是 char * 的各类调用,且使用 gcc 编译器编译链接的,例如 inet_ntoa。

4.调用 strerror 要有 #include ,调用 inet_ntoa 要有 #include

参考链接:

1.https://blog.csdn.net/yin138/article/details/50363248
2.https://www.cnblogs.com/acool/p/4708483.html


http://www.ngui.cc/el/5127073.html

相关文章

windows:配置多网卡路由表(规则)

windows:配置多网卡路由表(规则) 有时出差到中国移动研究院,既要连接到内网指定服务器工作,又希望能连接外网随时能查一些资料。 但是内网和外网不通的,如何配置笔记本能实现多网卡路由? 前置…

c/c :linux select 1024 文件描述符限制

c/c:linux select 1024 文件描述符限制 通常来说,linux下select调用要求文件描述符的值小于1024,也就是说,fd set中的每个文件描述符的值域为:[0,1023]。 如果超过,linux下select调用会发生什么ÿ…

lua:使用元表实现的一种面向对象方法调用

lua:使用元表实现的一种面向对象方法调用 一、lua中的面向对象编程 lua中,面向对象编程主要是通过table来实现的。 lua中,定义对象及方法: 冒号定义,冒号引用 local obj {}function obj:setname(name)self.name …

go:源码的修改、调试

go:源码的修改、调试 需求: 1.通过修改go源码逻辑,实现想要的自定义功能。 例如:修改go的net/http等相关包的代码,内嵌针对http请求/应答的原始消息输出到日志,方便定位排查。 2.临时修改go源码逻辑&am…

linux:常用压缩及解压缩命令

linux:常用压缩及解压缩命令 后缀:tar解包:tar xf redis-4.0.10.tar打包:tar cf redis-4.0.10.tar redis-4.0.10说明:-c, --createcreate a new archive-x, --extract, --getextract files from an archive-f, --filea…

mysql:查看mysql版本号

mysql:查看mysql版本号 方法一**【推荐】**: mysql> select version(); ----------- | version() | ----------- | 8.0.15 | ----------- 1 row in set (0.00 sec)方法二: mysql> status -------------- mysql ver 8.0.15 for l…

mysql:常用基本操作命令集

mysql:常用基本操作命令集 客户端使用帮助 $ mysql --help ……-p, --password[name] password to use when connecting to server. if password isnot given its asked from the tty.-p, --port# port number to use for connection or 0 for default to,…

informix:常用基本操作命令集

informix:常用基本操作命令集 1.表数据 1.1.导出 unload to data.out select * from table_name; 1.2.导入 load from data.out insert into table_name; 2.表结构导出 dbschema -d database_name -t table_name > table.sql 3.数据库结构导出 dbschema…

linux:调用gethostname返回enametoolong(file name too long)

linux:调用gethostname返回enametoolong(file name too long) 今天遇到特别奇怪的一个问题。 代码: main.c #include "util.h" #include #include #include #in…

c :map自定义键比较函数

c:map自定义比较函数 map容器可以自定义键比较函数。 例如,对某个map对象操作,键比较都忽略大小写,如下: main.c #include #include
网站地图