2017-08-29 28 views
29

从对this question的回答和意见中,我了解到getenv是由C++标准定义的,但setenv不是。实际上,下面的程序为什么getenv标准化但不是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 
} 

不能编译我(叮当3.9)。

为什么这些看起来互补的功能之一是标准化的,而不是其他的?

+0

POSIX'setenv()'和'getenv()'不是线程安全的,IIRC。也许以某种方式与此有关? – tambre

+2

@tambre令人怀疑,'std :: getenv'是线程安全的,因为C++ 11(根据cppreference) – Borgleader

+6

推测,但我会说是因为有一个相对简单的'std :: getenv'定义可以被标准化。串入,串出。补码不是那么直截了当,并且*非常*实现相关。 – StoryTeller

回答

30

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

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

rationale为C标准明确地说(§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的功能的历史部分)。奇怪的是,在Mac上运行MacOS的塞拉利昂10.12.6,man 3 setenv有标识历史部分:

功能SETENV()和unsetenv()出现在第7版AT &牛逼UNIX。 putenv()函数出现在4.3BSD-Reno中。

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

有在评论与Random832一些讨论,现在取出,提TUHS – The Unix Heritage Society为约古Unix版本的信息来源。该链包括我的观察:如果没有别的,这个讨论强调了为什么标准委员会做得好,以避免'设置环境'!看起来putenv()不在第7版UNIX中,与我的记忆相反。我相当肯定它在1983年使用的系统中可用,这是一个来自系统III的一些材料的第七版,有些来自PWB。它是SVR4的一部分(我有一个手册),并在SVID的某个版本中定义(可能在SVR4之前)。

C的基本原理还提到了关于gets()的担忧,但包括它,尽管有这些顾虑;当然,它(非常明智地)从C11中删除(但POSIX仍然指C99,而不是C11)。

+0

POSIX显然[不相信好东西](http://pubs.opengroup.org/onlinepubs/9699919799/functions/putenv.html)。 ;-) –

+3

对POSIX的约束与C上的约束不同;结果是不同的选择。 –

4

setenv是不可能的在一些原始环境C被定义。

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

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

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

+1

“*修改**调用**进程的状态*” - 真的吗? C可以指定这样的平台(如果它们存在的话)在它们的'getenv()'/'putenv()'实现中提供足够的隔离来实现每个进程环境的效果。 –

+3

@TobySpeight:他的意思是,处理发生对'getenv'的调用。 –

+0

啊,我明白了;我误解为父母的过程。感谢您指出这一点,@ Cheersandhth.-Alf –

相关问题