getenv ()
et envz_get ()
recherchent tous deux des variables d'environnement de la même source si cette dernière reçoit l'argument optionnel envp
à int main (int argc, char * argv [], char * envp [])
?
En d'autres termes, l'argument optionnel envp
de int main (int argc, char * argv [], char * envp [])
fait-il référence au même pool des variables d'environnement référencées par getenv ()
?
3 Réponses :
D'après mon expérience, oui, ils sont identiques. Il ne semble pas que getenv () serait particulièrement utile si ce n'était pas le cas. Ce n'est pas quelque chose que j'avais testé depuis des décennies, mais en réponse à votre question, je viens de lancer un test, et bien que getenv () soit autorisé par la norme à utiliser une zone de mémoire statique pour ses retours, ses valeurs de retour sont toutes indiquées au premier caractère après le signe égal dans le troisième argument de main. Je me souviens vaguement que cela s'est produit la dernière fois que j'ai fait ce test, même si c'était un système Unix différent.
Cela étant dit, en regardant la norme, ou aussi près que je peux raisonnablement y arriver ... De la dernière ébauche C17 proposée gratuitement:
La fonction getenv recherche dans une liste d'environnement, fournie par l'environnement hôte, une chaîne qui correspond à la chaîne pointée par son nom. L'ensemble des noms d'environnement et la méthode de modification la liste d'environnement est définie par l'implémentation. La fonction getenv n'a pas besoin d'éviter les courses de données avec d'autres threads d'exécution qui modifient la liste d'environnement. 305)
L'implémentation doit se comporter comme si aucune fonction de bibliothèque n'appelait la fonction getenv. Retour La fonction getenv renvoie un pointeur vers une chaîne associée au membre de liste correspondant. le la chaîne pointée ne doit pas être modifiée par le programme, mais peut être écrasée par un appel ultérieur à la fonction getenv. Si le nom spécifié est introuvable, un pointeur nul est renvoyé.
305) De nombreuses implémentations fournissent des fonctions non standard qui modifient la liste d'environnement.
Ce qui signifie en gros, probablement, mais le langage C ne le garantit pas exactement.
Ce qui suit prouve que envp
fait référence à un pool qui est au moins un sous-ensemble du pool dont getenv ()
puise; et j'ai tendance à penser qu'ils sont, en pratique, totalement identiques.
> g++ main.cpp && ./a.exe true
.
#include <iostream> #include <vector> int main( int argc, char* argv[], char* envp[] ) { std::vector<std::string> fromEnvP; while ( *envp ) fromEnvP.push_back( *envp++ ); std::vector<std::string> fromEnv; for( std::vector<std::string>::iterator i = fromEnvP.begin(); i != fromEnvP.end(); ++i ) { std::string::size_type pos = i->find( '=' ); std::string varname( i->substr( 0, pos ) ); fromEnv.push_back( varname + "=" + getenv( varname.c_str() ) ); } std::cout << std::boolalpha << ( fromEnvP == fromEnv ) << std::endl; return 0; }
Le programme compare le contenu du tableau envp
à ce que renvoie getenv
. Ceci n'est pas la question; envz_get
fait autre chose.
Les chaînes utilisées par les variables d'environnement dans l'état actuel du processus ne sont pas nécessairement en mémoire contiguë. Certaines variables d'environnement peuvent avoir été supprimées par le code de démarrage, ou modifiées ou ajoutées par un appel à putenv
ou setenv
. Ces modifications ne sont pas nécessairement reflétées dans le tableau de chaînes que envz_get
examine car elles sont effectuées en modifiant les pointeurs (et non les chaînes) dans le tableau d'environnement.
Voici un exemple qui le démontre:
removing: LESSCLOSE getenv (STY): 9173.pts-0.deneb envz_get (STY): 9173.pts-0.deneb getenv (LESSCLOSE): (null) envz_get (LESSCLOSE): /usr/bin/lesspipe %s %s
Sur mon système, il imprime ceci:
#include <assert.h> #include <envz.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main (int argc, char **argv, char **envp) { assert (envp[0] != NULL); assert (envp[1] != NULL); char *first_name = strndup (envp[0], strcspn (envp[0], "=")); char *second_name = strndup (envp[1], strcspn (envp[1], "=")); printf ("removing: %s\n", second_name); unsetenv (second_name); printf ("getenv (%s): %s\n", first_name, getenv (first_name)); size_t size = 0; for (size_t i = 0; envp[i] != NULL; ++i) size += strlen (envp[i]) + 1; printf ("envz_get (%s): %s\n", first_name, envz_get (envp[0], size, first_name)); printf ("getenv (%s): %s\n", second_name, getenv (second_name)); printf ("envz_get (%s): %s\n", second_name, envz_get (envp[0], size, second_name)); }
avez-vous essayé d'imprimer l'adresse du pointeur de chaque
envp
et de voir où il est stocké? C'est peut-être sur la pile.