为什么getenv标准化但不是setenv?

时间:2017-08-29 11:59:37

标签: c++ c language-lawyer

根据对this question的回答和评论,我了解getenv是由C ++标准定义的,但setenv不是。#include <cstdlib> #include <iostream> int main ( int argc, char **argv ) { std::cout << std::getenv("PATH") << std::endl; // no errors std::setenv("PATH", "/home/phydeaux/.local/bin:...", true); // error } 。事实上,以下计划

()

不为我编译(clang 3.9)。

为什么其中一个看似互补的功能是标准化的而不是另一个?

2 个答案:

答案 0 :(得分:30)

C90标准包括getenv();因此,C ++ 98标准也是如此。

最初创建C标准时,环境设置的先例为putenv(); setenv()函数直到稍后才被设计出来。标准委员会尽可能避免创建新功能,但也尽可能避免标准化有问题的功能(是的,localeconv()gets()是反例)。 putenv()的行为是有问题的。你必须传递它不是自动持续时间的内存,但你不知道你是否可以再次使用它。这就像是强制内存泄漏。这是一件很好的事情,putenv()没有标准化。

C标准的rationale明确说明(§7.20.4.5,p163):

  

标准中省略了相应的putenv函数,因为它在多进程环境之外的实用程序是有问题的,并且因为它的定义恰当是操作系统标准的域。

特定于平台的API介入并以适合他们的方式提供缺少的功能。

POSIX标准的第一版(1988年试用版; 1990年)未包括setenv()putenv()。 X / Open可移植性指南(XPG)问题1确实包括putenv()基于其在SVID(System V Interface Definition)中的外观 - 其中不包括setenv()。 XPG第6期添加了setenv()unsetenv()(请参阅链接到的URL处的函数的历史记录部分)。奇怪的是,在运行macOS Sierra 10.12.6的Mac上,man 3 setenv有一个历史记录部分,用于标识:

  

函数setenv()和unsetenv()出现在Version 7 AT&amp; T UNIX中。 putenv()函数出现在4.3BSD-Reno中。

这是出乎意料的,可能是错误的,因为UNIX Programmer's Manual Vol 1(1979)不包括putenv()setenv()unsetenv()中的任何一个。在80年代的某个阶段,putenv()函数被添加到Unix的AT&amp; T变体中;它是在SVID中并且在SVR4于1990年发布时记录并且可能是System III的一部分。我认为他们几乎已经扭转了平台。在第一个C和POSIX标准发布后,4.3BSD-Reno于1990年6月发布。

Random832的评论中进行了一些讨论,现已删除,并提及TUHS – The Unix Heritage Society作为有关古代Unix版本的信息来源。链条包括我的观察:如果不出意外,这个讨论强调了为什么标准委员会做得好以避免“设置环境”!似乎putenv()不在第7版UNIX中,与我的记忆相反。我很确定它可以在我从1983年使用的系统中获得,这是一个很多的第7版,其中一些材料来自System III,一些来自PWB。它是SVR4的一部分(我有一本手册),并且在某些版本的SVID中定义(可能在SVR4之前)。

C理由还提到了对gets()的担忧,但尽管存在这些担忧,但仍包括在内。当然(非常明智地)从C11中删除了(但是POSIX仍然指的是C99,而不是C11)。

答案 1 :(得分:4)

在某些原始环境中无法使用setenv {。{1}}。

getenv允许您查看您的环境。使用exec创建一个新进程[lv] [p] [e]允许您创建具有继承或新环境的子进程。

但是,setenv会修改调用进程的状态,这并非总是可行。

我想这是因为它增加了调用者的可写接口,并且最初并不需要,并且这些天存在安全风险。