8
votes

Execl () Arguments à Ubuntu

Je suis en train d'apprendre la programmation Linux et je suis tombé sur la fonction EXED qui est un peu très utile. Mais le problème est que les arguments de la fonction EXEC sont très déroutants et je ne parviens pas à saisir quel argument est à quelle usine .. Dans le code suivant Execl () La fonction est appelée à partir d'un enfant créé via Fourche () , quel est le but du dernier argument ( null ) dans exécuté () ? xxx

si On peut expliquer quel est le but de null argument et autres arguments et des arguments des arguments de EXEC () fonction familiale, ce serait une bonne aide pour moi!


0 commentaires

5 Réponses :


4
votes

Les fonctions exécutées sont variadic: elles prennent un nombre variable de paramètres afin de pouvoir transmettre un nombre variable d'arguments à la commande. Les fonctions doivent utiliser null en tant que marqueur pour marquer la fin de la liste d'arguments.

dans les fonctions variadiques est une boucle qui ira sur le nombre variable d'arguments. Ces boucles ont besoin d'une condition de terminaison. Dans certains cas, par exemple Printf , le nombre réel d'arguments peut être déduit d'un autre argument. Dans d'autres fonctions, null est utilisé pour marquer la fin de la liste.

Une autre option serait d'ajouter un paramètre de fonction supplémentaire pour Nombre d'arguments , mais cela rendrait le code un peu plus fragile, nécessitant au programmeur de gérer un paramètre supplémentaire plutôt que de toujours utiliser un null comme argument final.

vous Voir également (char *) 0 utilisé comme marqueur: xxx


2 commentaires

Le nombre et le type des arguments doit être d'accord avec ce que la fonction appelée attend. Comment la fonction appelée sait que l'attendre est documentée. Dans le cas de exécutant , la fonction appelée attend une liste de char * , terminée par un pointeur null de type char * . Étant donné que null a type int (ou au moins un type intégré), le transmettre ici est un comportement indéfini.


@Jameskanze à nouveau vous et vos comportements non définis ...



17
votes

créer un comportement indéfini. Ce n'est pas un appel juridique à exécutant . UNE Un appel correct peut être: xxx

Le dernier argument doit être (code> (char *) 0 ou vous avez un comportement non défini. Le premier argument est le chemin de l'exécutable. Ce qui suit Les arguments apparaissent dans argv du programme exécuté. La liste de ces Les arguments sont terminés par un (char *) 0 ; c'est comme ça que la fonction appelée sait que le dernier argument a été atteint. Dans l'exemple ci-dessus, Par exemple, l'exécutable à "/ bin / ls" remplacera votre code; dans son principal , il aura argc égal 2, avec argv [0] égal "ls" , et argv [1] égal "- l" .

immédiatement après cette fonction, vous devez avoir la manipulation des erreurs code. ( exécutant retourne toujours -1, quand il retourne, de sorte que vous n'avez pas besoin de Essaye-le. Et il ne renvoie que s'il y avait une sorte d'erreur.)


5 commentaires

Pourquoi pensez-vous exactement que d'utiliser null au lieu de (char *) 0 crée un comportement non défini?


@Janspurny parce que la norme POSIX le dit. Plus généralement, la norme C indique qu'il s'agit d'un comportement indéfini si une fonction Varargs tente d'extraire un type autre que le type qui a été passé. Execl est documenté pour nécessiter un char * . Cela pourrait difficilement essayer d'un autre type jusqu'à ce qu'il ait extrait l'argument. NULL a un type intégral, généralement int . Donc, passe null est un comportement indéfini et a été depuis déjà arrêté d'être INTS.


@Jameskanze: Des conneries totales. POSIX indique que null , sous forme de pointeur NULL, est zéro converti en un pointeur [définitions posix, 3.244], généralement (vide *) 0 . Il est (vide *) 0 ou une expression équivalente. Dans C89 et C99, VOID * n'a pas besoin d'être distribué à un autre type de pointeur. Par conséquent - et cela englobe Toutes les implémentations C89 / C99 / GNU C que j'ai jamais utilisées, à partir de microcontrôleurs à des clusters informatiques - null est la bonne à utiliser pour cela et toutes les autres fonctions variadiques similaires.


@Nominalanimal null n'est pas un pointeur NULL, c'est une constante de pointeur nulle. Et une constante de pointeur NULL est requise par la norme C ++ pour avoir un type intégral. J'ai seulement vu deux définitions de null dans UNIX: 0 et g ++ 's __ null compilateur magique. C'est toujours une erreur pour réussir null à une fonction variadique où les pointeurs sont attendus. La norme POSIX spécifie à l'aide de (char *) 0 et les pages de l'homme Linux indiquent explicitement que null doit être transmis comme (char *) null .


@Nominalanimal Juste pour être parfaitement clair, lorsque null (ou 0 ) est utilisé dans un contexte nécessitant un type de pointeur, il est implicitement converti en un pointeur null. Passer une dispute à un ... pas nécessite un type de pointeur, et aucune conversion ne se produit; Vous passez 0 . G ++ utilise compiler magique pour null , vous vous en tirerez probablement avec g ++, mais j'ai utilisé plus que quelques compilateurs où cela ne fonctionnerait pas; où char * était supérieur à un int (et null a été défini comme 0 ).



1
votes

dans /usr/include/libio.h , puisque GCC 2.8 (il y a longtemps) null est défini comme étant null ( est réservé aux cométine), avant que ce null était (vide *) 0 qui est indiscernable de (char *) 0 dans un Varargs Situation Depuis que le type n'est pas transmis, l'exception étant si __ cplusplus est défini dans quel cas null est défini comme 0.

La chose sécurisée à faire surtout si vous avez une architecture de 64 bits consiste à utiliser explicitement (void *) 0 qui est défini pour être compatible avec n'importe quel pointeur et ne s'appuie pas sur n'importe quel DODGY #defines qui pourrait arriver à être dans la bibliothèque standard.


0 commentaires

0
votes

Le but de l'argument de fin (char *) 0 est de terminer les paramètres. Le comportement indéfini peut entraîner une erreur si cela manque. La page man définit la signature exécutée comme: xxx

chemin : l'emplacement du programme à invoquer, le programme à invoquer. < / p>

arg , ... *: peut être considéré comme arg0, arg1, ..., argn.

dans votre cas exécutant ( "/ bin / ls", "ls", "-l", (char *) 0); est l'appel de fonction correct.

" bin / ls "Le programme à invoquer

" ls "Le nom du programme

" -l "est le paramètre de ce programme appelé


0 commentaires

0
votes

L'implémentation GLIBC-2.34 de la fonction POSIX EXECL CODE> EXECLL code> est celle ci-dessous.

char* p = 0;
argv[i] = p;
...


0 commentaires