我注意到,MS编译器为getenv
等cstdlib
函数提供了“不推荐使用”的警告。 MS发明了自己的标准,如_dupenv_s
。
AFAIK主要的“不安全”是关于重入*。 由于MS的CRT被标记为“multithreading”( /MT
),为什么他们不能用可重入的线程安全版本代替getenv
呢? 难道有人会依赖不安全的行为吗?
我用GCC编译了相同的代码g++ -Wall -Wextra -Weff++ -pedantic foo.cpp
,它不会产生任何警告。 所以我猜这在POSIX上不是问题? 这是如何解决的? (好吧,也许他们只是改变了getenv
的行为,很高兴有这个证实)。
* 这是一个过于笼统的说“它只是重入。 当然,我们有像strncpy_s
这样的完全改变签名和处理缓冲区大小的东西。 但是不改变这个问题的核心
在一个理智的世界里,答案将是“当然不会,那将是愚蠢的!” 然而,在这个世界上,似乎没有任何结局,没有经过认真考虑的无证行为,人们会依赖于这些行为。 Raymond Chen在他的博客中收集了很多这样的轶事(anecdon'ts?)。 比如在加载程序中使用一个bug的可恶的做法来共享exe和DLL之间的线程局部变量 。 当你拥有与微软一样多的客户时,唯一的安全选择就是从不冒险破坏向后兼容性。
警告的区别是因为cl.exe
将会突出显示一个潜在的安全问题,而g++
则不会。 getenv
和puts
和friends在POSIX下仍然被破坏,但是(至少对getenv
)在标准库中没有更安全的选择。 而且,与微软不同的是,GNU人可能会看到一个标准的库调用存在潜在的安全问题,而不是一个更安全的平台特定的库调用。
它惹恼了微软选择做这件事。 我知道如何安全地调用所有的功能,我不想或不需要这些额外的警告。
只需设置_CRT_SECURE_NO_WARNINGS并完成它。 这真的很愚蠢。
对于getenv
的具体情况,确实不是可重入的或线程安全的。 至于为什么微软不只是取代它,你不能接受这个接口,并使其可重入(你可以使用线程本地存储几乎使其“线程安全”,但它仍然不可重入)。
即使你只是把getenv
全部拿走,仍然有问题,你有environ
变量,这将需要一些严重的编译器级支持,使线程安全,因为它只是数据。
真的,如果你有多个线程的话,除了“在进程启动之前或在进程启动之前设置它,并且只从这个点开始读取”之外的其他任何东西,使用环境变量可能会结束。 setenv
和putenv
没有足够丰富的接口来表达“自动设置这组环境变量”,同样getenv
也没有办法表示“自动读取这组环境变量”。
在我看来, _dupenv_s
有点愚蠢,因为如果突然使用它,你的代码就会安全起来,或许可以用getenv以安全的方式完成。 _dupenv_s
解决了在多线程场景中使用环境变量的一小部分问题。