c++ c standards argv

c++ - ¿Es "argv[0]=name-of-executable" un estándar aceptado o simplemente una convención común?



command line arguments (7)

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 programa o ""

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

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?


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 programa, y ​​la mayoría de los otros programas siguen la misma convención, por lo que argv[0] suele ser el nombre del programa.

Pero un programa 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.


ISO-IEC 9899 establece:

5.1.2.2.1 Inicio del programa

Si el valor de argc es mayor que cero, la cadena apuntada por argv[0] representa el nombre del programa; argv[0][0] será el carácter nulo si el nombre del programa 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 programa .

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 <unistd.h> 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 <mach-o/dyld.h> 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.


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 programa; argv[0][0] será el carácter nulo si el nombre del programa no está disponible desde el entorno host.

Entonces, no, solo es el nombre del programa si ese nombre está disponible. Y "representa" el nombre del programa, no necesariamente es el nombre del programa. 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 programa.

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 programa 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 programa. 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.


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 programas 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.


Esta página dice:

El elemento argv [0] normalmente contiene el nombre del programa, pero esto no se debe confiar; de todos modos, es inusual que un programa 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 programa en sí. Esto permite que el programa descubra información sobre sí mismo. También agrega uno más a la matriz de argumentos de programa, por lo que un error común al obtener argumentos de línea de comandos es tomar argv [0] cuando desee argv [1].


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 <unistd.h> int main(void) { char *argv[] = {"yada yada", NULL}; char *envp[] = {NULL}; execve("b.out", argv, envp); }

bc

#include <stdio.h> int main(int argc, char **argv) { puts(argv[0]); }

Entonces:

gcc a.c -o a.out gcc b.c -o b.out ./a.out

Da:

yada yada

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

Probado en Ubuntu 16.10.