根据对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)。
为什么其中一个看似互补的功能是标准化的而不是另一个?
答案 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会修改调用进程的状态,这并非总是可行。
我想这是因为它增加了调用者的可写接口,并且最初并不需要,并且这些天存在安全风险。