¿Por qué necesitamos argc mientras siempre hay un nulo al final de argv?

116

Parece que argv[argc]es siempre NULL, así que creo que podemos recorrer la lista de argumentos sin argc. Un solo whilebucle hará esto.

Si siempre hay un NULLal final de argv, ¿por qué necesitamos un argc?

StarPinkER
fuente
17
Probablemente sea una cuestión de conveniencia. Brinda al programador una manera fácil de rescatar temprano si no hay suficientes argumentos, sin bucles. De lo contrario, seguramente tendríamos funciones llamadas int argc(char *argv[])haciendo exactamente esto :-))
cnicutar
5
Para ser claros, "\0"no es lo mismo que el puntero NULL ( 0es equivalente a NULL en C ++)
Mats Petersson
31
¿Por qué necesitamos que argv [argc] sea NULL si tenemos argc?
Ambroz Bizjak
7
¿De qué otra manera determinaría el número de argumentos en tiempo constante?
Avakar
4
No crea que las etiquetas linux / unix sean apropiadas aquí, ya que este comportamiento debería ser cierto para todos los compiladores en todos los sistemas operativos.
Darrel Hoffman

Respuestas:

106

Sí, argv[argc]==NULLestá garantizado. Ver C11 5.1.2.2.1 Inicio del programa (énfasis mío)

Si se declaran, los parámetros de la función principal obedecerán las siguientes restricciones:

El valor de argc no será negativo. argv [argc] será un puntero nulo.

argcPor lo tanto, proporcionar no es vital, pero sigue siendo útil. Entre otras cosas, permite comprobar rápidamente que se ha pasado el número correcto de argumentos.

Editar: la pregunta se ha modificado para incluir C ++. n3337 draft 3.6.1 La función principal dice

2 ... argc será el número de argumentos pasados ​​al programa desde el entorno en el que se ejecuta el programa. .... El valor de argc no será negativo. El valor de argv [argc] será 0 .

Simonc
fuente
36
Y argcpodría ser muy grande, ya que la cáscara se hace de expansión (por lo que en ls *el *se expande por el shell antes execvedel /bin/lsejecutable). En mi sistema, puedo tener argcvarios cientos de miles.
Basile Starynkevitch
Eso es muy bueno, esto nunca se me ocurrió ya que siempre lo consideré argcsuficiente, pero definitivamente puedo pensar en situaciones en las que esta garantía sería relevante e incluso necesaria. +1
Thomas
6
@BasileStarynkevitch El tiempo de simplemente recorrer una matriz de valores de puntero una vez más hasta NULL, para obtener el recuento, es minúsculo en comparación con el tiempo que ya se ha dedicado a generar la matriz de punteros, e incluso más irrelevante en comparación con el uso real de cada valor de argumento en el programa. Y si solo verifica si el recuento de argumentos es mayor que N, entonces no es necesario pasar por toda la matriz. Aún así, estoy totalmente de acuerdo, eso argcfue y es algo bueno.
Hyde
43

Sí, argv[argc]se garantiza que sea un puntero nulo. argcse utiliza por conveniencia.

Citando la explicación oficial de C99 Justificación, observe las palabras verificación redundante :

Justificación del estándar internacional - Lenguajes de programación - C §5.1.2.2.1 Inicio del programa

La especificación de argcy argvcomo argumentos para mainreconocer una práctica previa extensa. argv[argc]Se requiere que sea un puntero nulo para proporcionar una verificación redundante para el final de la lista, también sobre la base de la práctica común.

Yu Hao
fuente
19

Es por razones históricas y compatibilidad con código antiguo. Originalmente, no había garantía de que existiera un puntero nulo como último elemento de la matriz argv. Pero argc siempre ha existido.

Zentrunix
fuente
... Lo cual es una pena, en cierto modo. Si lo tuviéramos int main(char *argv[], int argc, ...), entonces algunos programas podrían simplemente omitir el argcporque no lo necesitan. Lo contrario (necesitando argcpero no argv) probablemente nunca sea útil en un programa real.
Hyde
@hyde: vea el comentario anterior de Basile Starynkevitch
zentrunix
6

Lo "necesitamos", porque es requerido por varios estándares.

Somos libres de ignorar el valor por completo, pero como es el primer parámetro de main, debemos tenerlo en la lista de parámetros. En C ++ (y probablemente en dialectos de C no estándar), puede simplemente omitir el nombre del parámetro, como este fragmento de C ++ (fácil de convertir a C):

#include <stdio.h> // C-compatible include, guarantees puts in global namespace

// program will print contents of argv, one item per line, starting from argv[0]

int main(int /*argc*/, char *argv[]) { // uncomment argc for C

    //(void)argc; // uncomment statement for C

    for (int i=0; argv[i]; ++i) {
        puts(argv[i]);
    }

    return 0;
}

En el estándar C, con configuraciones de advertencias comunes, el parámetro no utilizado genera una advertencia, que puede corregirse mediante una declaración como la (void)argc;que hace que el nombre se use sin generar ningún código.

argcEs bueno tenerlo, porque de lo contrario, muchos programas necesitarían recorrer los parámetros para obtener el recuento. Además, en muchos lenguajes de programación con matrices que tienen longitud, no hay ningún argcparámetro, solo hay una matriz con los elementos.

Hyde
fuente
La pregunta es sobre C y C ++. En C, se requiere el nombre del parámetro.