getpwnam函数异常行为排查:为何打印用户名重复?
问题分析:getpwnam调用引发的字符串输出异常
代码示例
#include <pwd.h> #include <stdio.h> #include <stdlib.h> int main(void) { printf("%s %s\n", getpwnam("steve")->pw_name, getpwnam("root")->pw_name); printf("%d %d\n", getpwnam("steve")->pw_uid, getpwnam("root")->pw_uid); return EXIT_SUCCESS; }
编译运行结果
$ gcc main.c && ./a.out steve steve 1000 0
异常现象
第8行代码尝试打印用户steve和root的用户名,却两次输出steve;第9行打印二者的UID,却能正常输出1000和0。
根本原因解析
1. getpwnam的静态内存特性
getpwnam函数返回的指针指向静态分配的内存区域,结构体中的pw_name字段同样指向该静态内存中的字符串。每次调用getpwnam时,新的用户信息会覆盖这块静态内存的内容。
2. C语言函数参数的求值顺序
C语言标准未规定函数参数的求值顺序,多数编译器(如GCC)默认采用从右到左的求值顺序。
针对第8行的printf调用:
- 编译器先求值右侧的
getpwnam("root")->pw_name:此时静态内存中存储root的信息,pw_name指向字符串root; - 接着求值左侧的
getpwnam("steve")->pw_name:静态内存被steve的信息覆盖,pw_name指向字符串steve; - 最后
printf读取两个pw_name指针,但这两个指针指向的是同一块被覆盖后的静态内存,因此两次输出都是steve。
而第9行的UID输出正常,原因在于pw_uid是整数类型:
- 不管参数求值顺序如何,每次调用
getpwnam时,都会将当前静态内存中的pw_uid数值取出并压入栈中; - 后续调用覆盖静态内存的UID值时,栈中已经保存了之前的数值,因此
printf能正确输出两个不同的UID。
补充说明:这是《Linux编程接口》习题8-1,原书问题存在错误,可查看官方修订版本。
内容的提问来源于stack exchange,提问作者Steve Lau
相关产品推荐
相关产品推荐

