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

Phy*_*aux 29 c c++ language-lawyer

这个问题的答案和评论中,我理解这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
}
Run Code Online (Sandbox Code Playgroud)

不为我编译(clang 3.9).

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

Jon*_*ler 30

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

最初创建C标准时,环境设定的先例是putenv(); setenv()直到后来才设计出这个功能.标准委员会在可能的情况下避免创建新功能,但也尽可能避免标准化有问题的功能(是的,localeconv()并且gets()是反例).行为putenv()是有问题的.你必须传递它不是自动持续时间的内存,但你不知道你是否可以再次使用它.这就像是强制内存泄漏.这是一个putenv()没有标准化的A Good Thing™ .

C标准的基本原理明确说明(§7.20.4.5,p163):

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

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


POSIX标准的第一版(1988年试用; 1990年)不包括setenv()putenv().X/Open可移植性指南(XPG)问题1确实包括putenv()它在SVID(系统V接口定义)中的外观- 其中没有包括setenv().该XPG问题6添加setenv()unsetenv()(见职能的历史部分,在连接到的URL).奇怪的是,在运行macOS Sierra 10.12.6的Mac上,man 3 setenv有一个历史部分标识:

函数setenv()和unsetenv()出现在第7版AT&T UNIX中.putenv()函数出现在4.3BSD-Reno中.

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

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

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

  • POSIX的约束与C上的约束不同; 结果是不同的选择. (3认同)

mks*_*eve 5

setenv 在某些C为其定义的原始环境中是不可能的。

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

然而,setenv 会修改调用进程的状态,这并不总是可行的。

我想这是因为它增加了调用者的可写接口,而最初是不需要的,现在是一个安全风险。

  • @TobySpeight:他的意思是,处理调用“getenv”的地方。 (3认同)