Подтвердить что ты не робот

Почему getenv стандартизован, но не 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
}

не компилируется для меня (clang 3.9).

Почему одна из этих, казалось бы, дополняющих функций стандартизирована, но не другая?

4b9b3361

Ответ 1

Стандарт C90 включает getenv(); поэтому также использовался стандарт С++ 98.

Когда первоначально был создан стандарт C, прецедент для настройки среды был putenv(); функция setenv() не была разработана до конца. Стандартный комитет избегал создавать новые функции, когда мог, но также избегал стандартизации проблемных функций, когда это возможно (да, localeconv() и gets() являются встречными примерами). Поведение putenv() проблематично. Вы должны передать ему память, которая не является автоматической продолжительностью, но вы не можете знать, сможете ли вы когда-либо использовать ее снова. Это похоже на вынужденную утечку памяти. Это была хорошая вещь, которая putenv() не была стандартизирована.

rationale для стандарта C явно говорит (§7.20.4.5, p163):

Соответствующая функция putenv была исключена из Стандарта, так как ее утилита вне многопроцессорной среды сомнительна и поскольку ее определение является надлежащим образом доменом стандарта операционной системы.

API-интерфейсы, специфичные для платформы, входят в систему и предоставляют недостающие функциональные возможности, подходящие для них.


Первые выпуски стандарта POSIX (1988 trial use, 1990) не включали setenv() или putenv(). Руководство по переносимости X/Open (XPG) Проблема 1 включила putenv() в зависимости от ее появления в SVID (Определение интерфейса V-интерфейса), который не включал setenv(). В XPG Issue 6 добавлены setenv() и unsetenv() (см. Разделы истории для функций по связанным URL). Любопытно, что на Mac, работающем под управлением macOS Sierra 10.12.6, man 3 setenv имеет раздел истории, который идентифицирует:

Функции setenv() и unsetenv() появились в версии 7 AT & T UNIX. Функция putenv() появилась в 4.3BSD-Reno.

Это неожиданно и, вероятно, ошибочно, поскольку Руководство для программиста UNIX Vol 1 (1979) не содержит ни одного из putenv(), setenv() или unsetenv(). Функция putenv() была добавлена ​​к вариантам AT & T Unix на некотором этапе 80-х годов; он был в SVID и документирован к тому времени, когда SVR4 был выпущен в 1990 году и, возможно, был частью System III. Я думаю, что у них почти нет платформы. 4.3BSD-Reno был выпущен в июне 1990 года после того, как были выпущены первые C и POSIX.

Было высказано некоторое обсуждение в комментариях с Random832, теперь удалено, отметив TUHS - Общество наследия Unix как источник информации о древних версиях Unix. Цепочка включала мое наблюдение: если ничего другого, в этом обсуждении подчеркивается, почему комитеты по стандартам преуспели, чтобы избегать "установления окружающей среды"! Похоже, что putenv() не было в 7-м выпуске UNIX, вопреки моей памяти. Я уверен, что он был доступен в системе, которую я использовал с 1983 года, в которой было много 7-го издания с некоторыми материалами из System III, некоторые из PWB. Это часть SVR4 (для этого есть руководство), и она была определена в некоторой версии SVID (вероятно, до SVR4).

В обосновании C также упоминаются проблемы, связанные с gets(), но включенные в него, несмотря на эти проблемы; Разумеется, он был (очень разумно) удален из C11 (но POSIX по-прежнему относится к C99, а не к C11).

Ответ 2

setenv невозможен в некоторых из исходных сред C.

getenv позволяет вам видеть вашу среду. создание нового процесса с помощью exec [l] [p] [v] [e] позволяет создать дочерний элемент с унаследованной или новой средой.

Однако setenv изменит состояние вызывающего процесса, что не всегда возможно.

Я предполагаю, что это связано с тем, что он увеличивает доступный для записи интерфейс для вызывающего абонента, и изначально он не был необходим, и в наши дни это угроза безопасности.