C 使用getpwnam()时静态分配的变量

C 使用getpwnam()时静态分配的变量,c,unix,C,Unix,我在学习系统编程 有很多函数返回静态分配的变量 其中之一是getpwnam() 因此,在我正在阅读的书籍示例中: printf(“%ld%ld\n”,(long)(getpwnam(“tsr”)->pw_-uid),(long)(getpwnam(“avr”)->pw_-uid)) 两者返回相同的uid,尽管在/etc/passwd中,它们的uid不同。 还有,解释一下原因 这就是问题所在 但是,我认为这是因为静态分配的变量。但是,结果是输出不同(例如,像30013005) 为什么输出不同 根据

我在学习系统编程

有很多函数返回静态分配的变量

其中之一是
getpwnam()

因此,在我正在阅读的书籍示例中:

printf(“%ld%ld\n”,(long)(getpwnam(“tsr”)->pw_-uid),(long)(getpwnam(“avr”)->pw_-uid))

两者返回相同的uid,尽管在
/etc/passwd
中,它们的uid不同。 还有,解释一下原因

这就是问题所在

但是,我认为这是因为静态分配的变量。但是,结果是输出不同(例如,像30013005)

为什么输出不同

根据这本书,输出应该是相同的

在函数中返回静态分配的变量是否与局部变量(自动变量)类似

例如:

char* func(const char** name)
{
    char str[256];
    strcpy(str,name);
    return str;
}

根据文档,
getpwnam
返回指向静态存储器的指针,随后调用
getpwent
getpwnam
getpwuid
可能会覆盖该指针。这就是为什么你看到了不一致的结果。作为建议,您可以使用这些函数的reentrent变体,
getpwnam_r
getpwuid_r
,将信息返回到用户提供的缓冲区,而不是静态缓冲区

在函数中返回静态分配的变量是否与局部变量(自动变量)类似

不同之处在于,静态存储的数据只初始化一次,并且在程序的整个生命周期中都存在,而自动变量只存在于它定义的块中。因此,在您的示例中,当函数
func
返回时,
str
数组不再存在,并且使用未定义的bahavior。在静态的情况下,这是正常的

char* func(const char** name)
{
    static char str[256];
    strcpy(str,name);
    return str;
}

但是请记住,使用静态数据通常会导致函数无法重新生成。

根据文档,
getpwnam
返回指向静态存储的指针,随后调用
getpwent
getpwnam
getpwuid
可能会覆盖该指针。这就是为什么你看到了不一致的结果。作为建议,您可以使用这些函数的reentrent变体,
getpwnam_r
getpwuid_r
,将信息返回到用户提供的缓冲区,而不是静态缓冲区

在函数中返回静态分配的变量是否与局部变量(自动变量)类似

不同之处在于,静态存储的数据只初始化一次,并且在程序的整个生命周期中都存在,而自动变量只存在于它定义的块中。因此,在您的示例中,当函数
func
返回时,
str
数组不再存在,并且使用未定义的bahavior。在静态的情况下,这是正常的

char* func(const char** name)
{
    static char str[256];
    strcpy(str,name);
    return str;
}

但请记住,使用静态数据通常会导致函数无法重新生成。

编译器可以自由调用
getpwname
,然后按其喜欢的顺序访问
pw\u uid
字段

例如,它可能会生成如下代码:

struct passwd *pw1 = getpwname("tsr");
struct passwd *pw2 = getpwname("avr");
long uid1 = pw1->pw_uid;
long uid2 = pw2->pw_uid;
printf("%ld %ld\n", uid1, uid2);
它将打印相同的数字,因为对
getpwname
的两个调用都返回指向相同
static
变量的指针,第二个调用将在我们有机会获得所需数据之前覆盖第一个调用编写的内容。这就是这本书所期望的情况

另一方面,编译器也可以选择执行以下操作

struct passwd *pw1 = getpwname("tsr");
long uid1 = pw1->pw_uid;
struct passwd *pw2 = getpwname("avr");
long uid2 = pw2->pw_uid;
printf("%ld %ld\n", uid1, uid2);
在这种情况下,在第二次调用
getpwname
之前,我们需要的信息(UID)保存在另一个变量中

必须强调的是,生成代码的两种方法对编译器都是合法的(从技术上讲,函数的参数之间没有序列点,因此副作用可能以任何顺序发生),因此您应该像第二个示例中那样显式编写代码,以确保它始终正常工作

(顺便说一句,通常最好通过支持这些函数的可重入版本来避免这些意外情况-例如,
getpwnam_r
不会返回指向静态数据的指针,该指针在下一次调用时被覆盖,而是填充您提供的结构)

在函数中返回静态分配的变量是否与局部变量(自动变量)类似

不完全是这样;返回指向局部变量的指针是非法的,因为当函数返回时,该变量“在逻辑上不再存在”,因此返回指向不再拥有的内存的指针;在实践中,每当它在堆栈上的位置被重用时(例如,在下一次函数调用时,或者在函数的后面),这样的内存就会被不相关的数据不可预测地覆盖


返回指向静态分配变量的指针(即全局变量或
静态变量
局部变量-实际上只是一个伪装的全局变量)相反,这是合法的——内存是你的,不会去任何地方——但由于它在对该函数的所有调用之间共享,因此在下一次调用该函数时,它肯定会被覆盖。这使得编写在嵌套调用中使用此类函数的代码变得非常复杂,而且线程安全或异步安全(如:在信号处理程序中可用)代码完全不可能

编译器可以自由调用
getpwname
,然后按照它喜欢的顺序访问
pw_uid
字段

例如,它可能会生成如下代码:

struct passwd *pw1 = getpwname("tsr");
struct passwd *pw2 = getpwname("avr");
long uid1 = pw1->pw_uid;
long uid2 = pw2->pw_uid;
printf("%ld %ld\n", uid1, uid2);
它将打印相同的数字,因为对
getpwname
的两个调用都返回指向相同
static
变量的指针,第二个调用将在我们有机会获得所需数据之前覆盖第一个调用编写的内容。这就是这本书所期望的情况

另一方面,编译器也可以选择执行以下操作

struct passwd *pw1 = getpwname("tsr");
long uid1 = pw1->pw_uid;
struct passwd *pw2 = getpwname("avr");
long uid2 = pw2->pw_uid;
printf("%ld %ld\n", uid1, uid2);
在这种情况下,信息提供者