¿Es “argv = name-of-executable” un estándar aceptado o simplemente una convención común?

Al pasar el argumento a main() en una aplicación C o C ++, ¿ argv[0] siempre será el nombre del ejecutable? ¿O es solo una convención común y no está garantizado que sea cierto el 100% del tiempo?

Las conjeturas (incluso las suposiciones educadas) son divertidas, pero realmente necesita ir a los documentos estándar para estar seguro. Por ejemplo, los estados de ISO C11 (mi énfasis):

Si el valor de argc es mayor que cero, la cadena apuntada por argv[0] representa el nombre del progtwig; argv[0][0] será el carácter nulo si el nombre del progtwig no está disponible desde el entorno host.

Entonces, no, solo es el nombre del progtwig si ese nombre está disponible. Y “representa” el nombre del progtwig, no necesariamente es el nombre del progtwig. La sección anterior dice:

Si el valor de argc es mayor que cero, los miembros de la matriz argv[0] a argv[argc-1] inclusive contendrán punteros a las cadenas, que reciben los valores definidos por la implementación por el entorno de host antes del inicio del progtwig.

Esto no ha cambiado desde C99, el estándar anterior, y significa que incluso los valores no están dictados por el estándar; depende de la implementación por completo.

Esto significa que el nombre del progtwig puede estar vacío si el entorno del host no lo proporciona, y cualquier otra cosa si el entorno del host lo proporciona, siempre que “cualquier otra cosa” de alguna manera represente el nombre del progtwig. En mis momentos más sádicos, consideraría traducirlo al swahili, ejecutarlo a través de un cifrado de sustitución y luego almacenarlo en orden inverso de bytes :-).

Sin embargo, definido por implementación tiene un significado específico en los estándares ISO, la implementación debe documentar cómo funciona. Así que incluso UNIX, que puede poner todo lo que le gusta en argv[0] con la familia de llamadas del exec , tiene que (y lo hace) documentarlo.

En los sistemas de tipo *nix con llamadas exec*() , argv[0] será lo que argv0 la persona que llama en el punto argv0 en la llamada exec*() .

El shell usa la convención de que este es el nombre del progtwig, y ​​la mayoría de los otros progtwigs siguen la misma convención, por lo que argv[0] suele ser el nombre del progtwig.

Pero un progtwig Unix deshonesto puede llamar a exec() y hacer argv[0] lo que quiera, así que no importa lo que diga el estándar C, no puede contar con este 100% del tiempo.

De acuerdo con el Estándar C ++, sección 3.6.1:

argv [0] será el puntero al carácter inicial de un NTMBS que representa el nombre utilizado para invocar el progtwig o “”

Entonces no, no está garantizado, al menos por el estándar.

Esta página dice:

El elemento argv [0] normalmente contiene el nombre del progtwig, pero esto no se debe confiar; de todos modos, es inusual que un progtwig no sepa su propio nombre.

Sin embargo, otras páginas parecen respaldar el hecho de que siempre es el nombre del ejecutable. Este afirma:

Notarás que argv [0] es la ruta y el nombre del progtwig en sí. Esto permite que el progtwig descubra información sobre sí mismo. También agrega uno más a la matriz de argumentos de progtwig, por lo que un error común al obtener argumentos de línea de comandos es tomar argv [0] cuando desee argv [1].

ISO-IEC 9899 establece:

5.1.2.2.1 Inicio del progtwig

Si el valor de argc es mayor que cero, la cadena apuntada por argv[0] representa el nombre del progtwig; argv[0][0] será el carácter nulo si el nombre del progtwig no está disponible desde el entorno host. Si el valor de argc es mayor que uno, las cadenas apuntadas por argv[1] a argv[argc-1] representan los parámetros del progtwig .

También he usado:

 #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) */ 

Y luego solo tiene que analizar la cadena para extraer el nombre del ejecutable de la ruta.

No estoy seguro de si se trata de una convención o estándar casi universal, pero de cualquier forma debes cumplirlo. Sin embargo, nunca lo he visto explotado fuera de los sistemas Unix y Unix. En los entornos de Unix, y tal vez particularmente en los viejos tiempos, los progtwigs pueden tener comportamientos significativamente diferentes según el nombre bajo el cual se invocan.

EDITADO: Veo en otras publicaciones al mismo tiempo que la mía que alguien ha identificado que proviene de un estándar en particular, pero estoy seguro de que la convención es anterior al estándar.

Runnable POSIX execve ejemplo donde argv[0] != Nombre ejecutable

Otros mencionaron al exec , pero aquí hay un ejemplo ejecutable.

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]); } 

Entonces:

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

Da:

 yada yada 

Sí, argv[0] también podría ser:

  • NULL: ¿ Cuándo puede argv [0] tener nulo?
  • empty: ¿Puede argv [0] contener una cadena vacía?

Probado en Ubuntu 16.10.

    Intereting Posts