char *envp[]作为main()的第三个参数可移植吗?

85
为了在 C 程序中获取环境变量,可以使用以下方法:
  • getenv()
  • extern char **environ;
但除了上述方法之外,是否使用 char *envp[] 作为传递给 main() 的第三个参数来获取环境变量也被视为标准的一部分?
#include <stdio.h>

int main(int argc, char *argv[], char *envp[])
{
    while(*envp)
        printf("%s\n",*envp++);
}

char *envp[]是否可移植?

4个回答

72

getenv 函数是 C 标准中唯一指定的函数。函数 putenv 和外部变量 environ 是 POSIX 特有的。

编辑

main 参数 envp 并非由POSIX指定,但得到广泛支持。

另一种访问环境列表的方法是在 main() 函数中声明第三个参数:

int main(int argc, char *argv[], char *envp[])

然后可以像处理environ一样处理此参数,不同之处在于其作用域仅限于main()。尽管这个特性在UNIX系统上得到了广泛实现,但应避免使用,因为除了作用域限制外,它在SUSv3中没有被指定。


10
请注意,C语言标准承认这是一种常见的替代方式——即使在C89的附录G(可移植性问题)中也提到了它;在C99和C11中的附录J(可移植性问题)中也有这个内容。 - Jonathan Leffler
它无法在IBM主机的z/OS 2.4和xlc/c99/c89上运行(至少如此)。有一个POSIX解决方案 - ben

23

它不具备可移植性。 *envp[] 是一个传统的UNIX特性,而不是所有现代UNIX系统都实现了它。

另外顺带一提,你可以通过对*argv[]进行指针遍历来访问envp,但我认为这不能被视为安全的编程方式。如果你查看进程内存映射,你会发现envp[]就在argv[]的上方。


6
你可以超越环境并检查auxv... ;-) - R.. GitHub STOP HELPING ICE
通常在auxv中存储什么内容?因为我最近想知道为什么envp之后的字段是常量(在运行之间)。 - skyel
1
elf.h 中查找以 AT_ 开头的宏。一些更有趣的内容包括 AT_SECUREAT_RANDOMAT_EXECFNAT_HWCAP 以及 uid/gid 相关的内容。否则,它们主要与动态链接器和 libc 初始化代码相关。auxv 的格式是系统字大小整数对,第一个整数是 AT_ 常量之一(标签),第二个整数是与该标签相关联的值(可能是指针,具体取决于标签)。 - R.. GitHub STOP HELPING ICE
1
使用指针查找argv的末尾,再往前走一步怎么样?char **find = argv, **envp; while(*find) find++; envp = find + 1; 可能是未定义行为,因为操作系统不能保证将环境信息放在argv的最后一个参数之后... - Braden Best
上一条评论的更传统/惯用且简洁的版本:char **envp = argv; while(*envp++); - mtraceur

19
标准描述了两种main格式(请参见C99标准(pdf)中的5.1.2.2.1节):
a)int main(void) b)int main(int argc,char **argv)或等效形式
它允许实现定义其他格式(可以允许第三个参数),也可以以其他实现定义的方式进行。

8
一个实现可能会为 main 提供更多的格式,但这两个是任何宿主实现中都保证存在的唯一格式。 - Daniel Fischer

11

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接