Aus Antworten und Kommentaren zu dieser Frage verstehe ich das getenv
ist durch den C++-Standard definiert, aber setenv
ist nicht. Und zwar das folgende Programm
#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
}
lässt sich bei mir nicht kompilieren (clang 3.9).
Warum wurde eine dieser scheinbar komplementären Funktionen standardisiert, die andere jedoch nicht?
Der C90-Standard beinhaltet getenv()
; Daher tat dies auch der C++98-Standard.
Als der C-Standard ursprünglich erstellt wurde, war der Präzedenzfall für die Umgebungseinstellung putenv()
; das setenv()
Funktion wurde erst später entwickelt. Das Standardkomitee vermied es, neue Funktionen zu erstellen, wenn es möglich war, vermied es aber auch, problematische Funktionen zu standardisieren (ja, localeconv()
und gets()
sind Gegenbeispiele). Das Verhalten von putenv()
ist problematisch. Sie müssen ihm Speicher übergeben, der nicht von automatischer Dauer ist, aber Sie können nicht wissen, ob Sie ihn jemals wieder verwenden können. Es ist wie ein erzwungenes Speicherleck. Das war A Good Thing™ putenv()
war nicht standardisiert.
Das Begründung für den C-Standard heißt es explizit (§7.20.4.5, p163):
Ein entsprechendes putenv
Die Funktion wurde aus dem Standard weggelassen, da ihre Nützlichkeit außerhalb einer Mehrprozessumgebung fraglich ist und da ihre Definition eigentlich die Domäne eines Betriebssystemstandards ist.
Plattformspezifische APIs springen ein und stellen die fehlende Funktionalität in für sie geeigneter Weise bereit.
Die ersten Ausgaben des POSIX-Standards (1988 Trial Use; 1990) enthielten keine setenv()
oder putenv()
. Der X/Open-Portabilitätsleitfaden (XPG) Ausgabe 1 enthalten putenv()
basierend auf seinem Erscheinen in der SVID (System-V-Schnittstellendefinition) – was nicht enthalten war setenv()
. Die XPG Ausgabe 6 hinzugefügt setenv()
und unsetenv()
(siehe die History-Abschnitte für die Funktionen unter den verlinkten URLs). Seltsamerweise auf einem Mac mit macOS Sierra 10.12.6, man 3 setenv
hat einen Verlaufsabschnitt, der Folgendes identifiziert:
Die Funktionen setenv() und unsetenv() erschienen in Version 7 von AT&T UNIX. Die Funktion putenv() erschien in 4.3BSD-Reno.
Dies ist unerwartet und wahrscheinlich fehlerhaft, da die UNIX Programmierhandbuch Band 1 (1979) enthält keine von putenv()
, setenv()
oder unsetenv()
. Das putenv()
Die Funktion wurde irgendwann in den 80er Jahren zu den AT&T-Varianten von Unix hinzugefügt; Es war in der SVID und dokumentiert, als SVR4 1990 veröffentlicht wurde, und war möglicherweise Teil von System III. Ich denke, sie haben fast die Plattformen umgekehrt. 4.3BSD-Reno wurde im Juni 1990 veröffentlicht, nachdem sowohl der erste C- als auch der POSIX-Standard veröffentlicht worden waren.
Es gab einige Diskussionen in Kommentaren mit Random832 , die jetzt entfernt wurden, und erwähnte TUHS – Die Unix Heritage Society als Informationsquelle über alte Unix-Versionen. Die Kette beinhaltete meine Beobachtung: Nicht zuletzt verdeutlicht diese Diskussion, warum die Normungsgremien gut daran getan haben, sich von „Setting the Environment“ fernzuhalten! Anscheinend putenv()
war entgegen meiner Erinnerung nicht in der 7. Ausgabe von UNIX. Ich bin mir ziemlich sicher, dass es in einem System verfügbar war, das ich ab 1983 verwendet habe, das war eine Menge 7. Ausgabe mit etwas Material von System III, einiges von PWB. Es ist ein Teil von SVR4 (dafür habe ich ein Handbuch) und wurde in einer Version der SVID definiert (wahrscheinlich vor SVR4).
Die C-Begründung erwähnt auch Bedenken hinsichtlich gets()
aber trotz dieser Bedenken aufgenommen; es wurde natürlich (sehr vernünftig) aus C11 entfernt (aber POSIX bezieht sich immer noch auf C99, nicht auf C11).
setenv ist in einigen der ursprünglichen Umgebungen nicht möglich C
definiert wurde für.
getenv ermöglicht es Ihnen, Ihre Umgebung zu sehen. Erstellen eines neuen Prozesses mit exec[lv][p][e] ermöglicht es Ihnen, ein untergeordnetes Element mit einer geerbten oder neuen Umgebung zu erstellen.
setenv würde jedoch den Status des aufrufenden Prozesses ändern, was nicht immer möglich war.
Ich denke, es liegt daran, dass es die beschreibbare Schnittstelle für den Anrufer vergrößert und ursprünglich nicht benötigt wurde und heutzutage ein Sicherheitsrisiko darstellt.
@tambre Zweifelhaft,
std::getenv
ist threadsicher seit C++11 (laut cpreference)– Borgführer
29. August 2017 um 12:05 Uhr
Spekulation, aber ich würde sagen, weil es eine relativ einfache Definition von gibt
std::getenv
das kann standardisiert werden. Saite rein, Saite raus. Die Ergänzung ist nicht so einfach, und ist sehr Umsetzung abhängig.– StoryTeller – Unslander Monica
29. August 2017 um 12:05 Uhr
Das C-Standard spiegelt dies wider. Es gibt 7.22.4.6 Die
getenv
Funktionaber kein entsprechendessetenv()
. Welche Logik auch immer existiert, um es in C++ wegzulassen, es ist wahrscheinlich auch auf C anwendbar. Daher habe ich das C-Tag hinzugefügt. (Und das Sprachanwalt-Tag …)– Andreas Henle
29. August 2017 um 12:07 Uhr
Ich stimme den Spekulationen von @StoryTeller zu und ich denke, es gibt keine endgültige Antwort, daher stimme ich dafür, als “hauptsächlich meinungsbasiert” zu schließen, obwohl die Frage in der Tat interessant ist …
– Benutzer2371524
29. August 2017 um 12:13 Uhr
Ich habe für die Wiedereröffnung gestimmt – nicht dass es einen großen Unterschied macht – denn wie sich herausstellt, gibt es ein Dokument, das eine Begründung für die Auslassung einer sehr verwandten Funktion enthält.
– Daniel Jour
29. August 2017 um 17:46 Uhr