Est-ce que «argv = nom-de-l’exécutable» est une norme acceptée ou simplement une convention commune?

Lorsque vous passez un argument à main() dans une application C ou C ++, argv[0] sera-t-il toujours le nom de l’exécutable? Ou est-ce juste une convention commune et non garantie d’être vraie 100% du temps?

Les devinettes (même les devinettes bien éduquées) sont amusantes, mais vous devez vraiment consulter les documents standard pour vous en assurer. Par exemple, la norme ISO C11 indique (je souligne):

Si la valeur de argc est supérieure à zéro, la chaîne pointée par argv[0] représente le nom du programme; argv[0][0] sera le caractère nul si le nom du programme n’est pas disponible dans l’environnement hôte.

Donc non, c’est seulement le nom du programme si ce nom est disponible. Et il “représente” le nom du programme, pas nécessairement le nom du programme. La section précédente qui indique:

Si la valeur de argc est supérieure à zéro, les membres du tableau argv[0] à argv[argc-1] inclus doivent contenir des pointeurs vers des chaînes, auxquelles l’environnement hôte atsortingbue des valeurs définies par l’implémentation avant le démarrage du programme.

Ceci est inchangé par rapport à la norme C99, la norme précédente, et signifie que même les valeurs ne sont pas dictées par la norme – cela dépend entièrement de la mise en œuvre.

Cela signifie que le nom du programme peut être vide si l’environnement hôte ne le fournit pas, et toute autre chose si l’environnement hôte le fournit, à condition que “quelque chose d’autre” représente en quelque sorte le nom du programme. Dans mes moments les plus sadiques, je considérerais de le traduire en swahili, en le faisant passer par un chiffrement de substitution puis en le stockant dans l’ordre des octets inversés :-).

Cependant, la définition ISO a une signification spécifique dans les normes ISO – la mise en œuvre doit documenter son fonctionnement. Ainsi, même UNIX, qui peut mettre tout ce qu’il aime dans argv[0] avec la famille d’appels exec , doit le documenter.

Sous les systèmes de type *nix avec des appels exec*() , argv[0] sera ce que l’appelant argv0 dans l’ argv0 l’ argv0 exec*() .

Le shell utilise la convention selon laquelle il s’agit du nom du programme, et la plupart des autres programmes suivent la même convention, donc argv[0] généralement au nom du programme.

Mais un programme Unix malhonnête peut appeler exec() et créer argv[0] comme il veut, donc peu importe ce que dit le standard C, vous ne pouvez pas compter sur 100% du temps.

Selon la norme C ++, section 3.6.1:

argv [0] sera le pointeur sur le caractère initial d’un NTMBS qui représente le nom utilisé pour appeler le programme ou “”

Donc non, ce n’est pas garanti, du moins par la norme.

Cette page indique:

L’élément argv [0] contient normalement le nom du programme, mais il ne faut pas s’y fier – de toute façon, il est inhabituel qu’un programme ne connaisse pas son propre nom!

Cependant, d’autres pages semblent sauvegarder le fait que c’est toujours le nom de l’exécutable. Celui-ci déclare:

Vous remarquerez que argv [0] est le chemin et le nom du programme lui-même. Cela permet au programme de découvrir des informations sur lui-même. Il ajoute également un élément au tableau des arguments du programme, alors une erreur commune lors de la récupération des arguments de ligne de commande est de récupérer argv [0] lorsque vous voulez argv [1].

ISO-IEC 9899 déclare:

5.1.2.2.1 Démarrage du programme

Si la valeur de argc est supérieure à zéro, la chaîne pointée par argv[0] représente le nom du programme; argv[0][0] sera le caractère nul si le nom du programme n’est pas disponible dans l’environnement hôte. Si la valeur de argc est supérieure à un, les chaînes pointées par argv[1] via argv[argc-1] représentent les parameters du programme .

J’ai aussi utilisé:

 #if defined(_WIN32) static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity) { return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity); } #elif defined(__linux__) /* elif of: #if defined(_WIN32) */ #include  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity) { size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1); pathName[pathNameSize] = '\0'; return pathNameSize; } #elif defined(__APPLE__) /* elif of: #elif defined(__linux__) */ #include  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity) { uint32_t pathNameSize = 0; _NSGetExecutablePath(NULL, &pathNameSize); if (pathNameSize > pathNameCapacity) pathNameSize = pathNameCapacity; if (!_NSGetExecutablePath(pathName, &pathNameSize)) { char real[PATH_MAX]; if (realpath(pathName, real) != NULL) { pathNameSize = strlen(real); strncpy(pathName, real, pathNameSize); } return pathNameSize; } return 0; } #else /* else of: #elif defined(__APPLE__) */ #error provide your own implementation #endif /* end of: #if defined(_WIN32) */ 

Et puis il vous suffit d’parsingr la chaîne pour extraire le nom de l’exécutable du chemin.

Je ne suis pas sûr que ce soit une convention presque universelle ou une norme, mais de toute façon, vous devriez vous y conformer. Je ne l’ai jamais vu exploité en dehors des systèmes Unix et Unix, cependant. Dans les environnements Unix – et peut-être particulièrement dans les anciens environnements – les programmes peuvent avoir des comportements très différents selon le nom sous lequel ils sont appelés.

EDITED: Je vois d’autres articles en même temps que le mien que quelqu’un l’a identifié comme provenant d’une norme particulière, mais je suis sûr que la convention est antérieure à la norme.

L’exécutable exécutable POSIX execve exemple où argv[0] != Nom de l’exécutable

D’autres ont mentionné exec , mais voici un exemple utilisable.

ac

 #define _XOPEN_SOURCE 700 #include  int main(void) { char *argv[] = {"yada yada", NULL}; char *envp[] = {NULL}; execve("b.out", argv, envp); } 

bc

 #include  int main(int argc, char **argv) { puts(argv[0]); } 

Alors:

 gcc ac -o a.out gcc bc -o b.out ./a.out 

Donne:

 yada yada 

Oui, argv[0] pourrait aussi être:

  • NULL: Quand argv [0] peut-il avoir une valeur nulle?
  • empty: argv [0] peut-il contenir une chaîne vide?

Testé sur Ubuntu 16.10.