2

C标准说:

getenv 函数返回一个指向与匹配列表成员关联的字符串的指针。指向的字符串不应被程序修改,但可能会被后续调用 getenv 函数覆盖。

据我了解,glibc 中的 getenv 实现(我使用的是 2.17 版)从名为char **environ的全局变量返回元素。对 getenv 函数的每个后续调用仍会返回此数组中的一个元素(或当此类 env 变量不存在时返回 null),而不会更改任何先前返回的值。

使用 glibc 时,后续调用 getenv 函数是否可以更改以前由 getenv 函数返回的指针的内容?如果是,什么时候?

4

3 回答 3

2

如果我理解正确,getenv理论上可以通过将字符串复制到其内部静态缓冲区并返回指向它的指针而不是提供指向environ成员的指针来实现。getenv如果是这样,则每次调用都会更改字符串。

于 2013-11-02T19:58:00.897 回答
2

这实际上只是标准中的一个错误。甚至 C11 也保留允许覆盖缓冲区的语言,但同时,它不允许与其他调用的数据竞争getenv,只允许修改环境的(实现定义的)函数,因此允许这种覆盖发生似乎矛盾的。

在所有现实世界的实现中,包括 glibc,getenv返回指向环境内部表示中字符串副本的指针,并且永远不会失效,除非您调用修改环境的函数。

于 2013-11-02T20:02:14.597 回答
2

也许演示会有所帮助:

char *getenv(const char *var){
    int i=0, len=strlen(var);
    if (!environ||!*var||strchr(var,'='))
        return NULL;
    while ( environ[i] && (environ[i][len] != '=' || strncmp(var,environ[i],len)) )
        i++;
    return (environ[i])? environ[i]+len+1 : NULL;
}

每次调用都会得到一个指向全局外部二维数组的适当指针environ,这就是程序不应该修改它的原因,因为它实际上会修改环境变量;但是随后对 getenv 的调用可能会在不同的位置获得值(如果 setenv 或 putenv 已更改它)

请注意,您正在获得一个指向字符串中间的指针。想想如果你改变它会发生什么。然后在任何给定点 **environ 可能会更改,以便地址指向其他变量(或垃圾)......如果您需要长期使用该字符串,您应该复制它以确保安全(尤其是在线程环境中)

它的意思是你可以mycharptr=getenv("myvar");随心所欲地做,这是安全的,但不要这样做mycharptr=getenv("myvar");mycharptr[0]='\0'; ... mycharptr=getenv("myvar");……否则你可能会得到意想不到的结果。

于 2013-11-02T20:03:36.417 回答