c - estándar - que tipo de kernel es linux
¿Puede argc ser cero en un sistema POSIX? (6)
Las primeras propuestas requerían que el valor de argc pasado a main () fuera "uno o más". Esto fue impulsado por el mismo requisito en los borradores del estándar ISO C. De hecho, las implementaciones históricas han pasado un valor de cero cuando no se proporcionan argumentos al llamador de las funciones ejecutivas. Este requisito se eliminó del estándar ISO C y posteriormente también se eliminó de este volumen de POSIX.1-2017. La redacción, en particular el uso de la palabra debería, requiere que una aplicación POSIX estrictamente conforme pase al menos un argumento a la función ejecutiva, garantizando así que argc sea uno o más cuando se invoque por dicha aplicación. De hecho, esta es una buena práctica, ya que muchas aplicaciones existentes hacen referencia a argv [0] sin verificar primero el valor de argc.
El requisito de una aplicación POSIX estrictamente conforme también establece que el valor pasado como primer argumento sea una cadena de nombre de archivo asociada con el proceso que se está iniciando. Aunque algunas aplicaciones existentes pasan una ruta de acceso en lugar de una cadena de nombre de archivo en algunas circunstancias, una cadena de nombre de archivo es más generalmente útil, ya que el uso común de argv [0] es en la impresión de diagnósticos. En algunos casos, el nombre de archivo pasado no es el nombre de archivo real del archivo; por ejemplo, muchas implementaciones de la utilidad de inicio de sesión utilizan una convención de prefijar un (''-'') al nombre de archivo real, lo que indica al intérprete de comandos que se invoca que es un "shell de inicio de sesión".
Además, tenga en cuenta que la prueba y [las utilidades requieren cadenas específicas para que el argumento argv [0] tenga un comportamiento determinista en todas las implementaciones.
¿Puede argc ser cero en un sistema POSIX?
Sí, pero no sería estrictamente conforme a POSIX.
Dada la definición estándar para el programa principal:
int main(int argc, char *argv[]) {
...
}
¿En qué circunstancias puede
argc
ser cero en un sistema POSIX?
Para agregar a las otras respuestas, no hay nada en C (POSIX o no) que impida que main () se llame como una función dentro del programa.
int main(int argc, int argv[]) {
if (argc == 0) printf("Hey!/n");
else main(0,NULL);
return 0;
}
Sí, es posible. Si llama a su programa de la siguiente manera:
execl("./myprog", NULL, (char *)NULL);
O alternativamente:
char *args[] = { NULL };
execv("./myprog", args);
Luego, en "myprog",
argc
será 0.
El estándar
también permite específicamente un 0
argc
como se señala en la sección 5.1.2.2.1 con respecto al inicio del programa en un entorno alojado:
1 La función llamada al inicio del programa se denomina
main
. La implementación no declara ningún prototipo para esta función. Se definirá con un tipo de retorno deint
y sin parámetros:
int main(void) { /* ... */ }
o con dos parámetros (referidos aquí como
argc
yargv
, aunque se pueden usar nombres, ya que son locales para la función en la que se declaran):
int main(int argc, char *argv[]) { /* ... */ }
o equivalente; o de alguna otra manera definida por la implementación.
2 Si se declaran, los parámetros de la función
main
obedecerán las siguientes restricciones:
- El valor de
argc
no será negativo.argv[argc]
será un puntero nulo....
Tenga en cuenta también que esto significa que si
argc
es 0, entonces se garantiza que
argv[0]
será NULL.
Sin
printf
forma en que
printf
trata un puntero NULL cuando se usa como argumento para un especificador
%s
no se detalla en el estándar.
Muchas implementaciones generarán "(nulo)" en este caso, pero no creo que esté garantizado.
Sí, puede ser cero, lo que significa que
argv[0] == NULL
.
Es una convención que
argv[0]
es el nombre del programa.
Puede tener
argc == 0
si inicia el binario, como con
execve
family y no da ningún argumento.
Incluso puede dar una cadena que no esté cerca del nombre del programa.
Es por eso que usar
argv[0]
para obtener el nombre del programa no es del todo confiable.
Por lo general, el shell donde escribe su línea de comandos siempre agrega el nombre del programa como primer argumento, pero nuevamente, es una convención.
Si
argv[0]
== "--help" y usa la opción
getopt
para analizar, no lo detectará porque
optind
se inicializa en 1, pero puede establecer
optind
en 0, use
getopt
y la opción larga "help" mostrará arriba.
larga historia corta: es perfectamente posible tener
argc == 0
(
argv[0]
no es realmente especial por sí mismo).
Sucede cuando el lanzador no da argumentos en absoluto.
TL; DR: Sí,
argv[0]
puede ser NULL, pero no por ninguna razón buena / sensata que conozca.
Sin embargo, hay razones para no preocuparse si
argv[0]
es NULL y para permitir específicamente que el proceso se bloquee si lo es.
Sí,
argv[0]
puede ser NULL en un sistema POSIX, si y solo si se ejecutó sin ningún argumento.
La pregunta práctica más interesante es si su programa debe preocuparse .
La respuesta a eso es
"No, su programa puede asumir que
argv[0]
no es NULL"
, porque algunas utilidades del sistema (utilidades de línea de comandos) no funcionan o funcionan de manera no determinista, cuando
argv[0] == NULL
, pero lo más importante, no hay una buena razón (aparte de la estupidez o los propósitos nefastos) por qué cualquier proceso haría eso.
(No estoy seguro si el uso estándar de
getopt()
también falla entonces, pero no esperaría que funcione).
Una gran cantidad de código, y de hecho la mayoría de los ejemplos y utilidades que escribo, comienzan con el equivalente de
int main(int argc, char *argv[])
{
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
printf("Usage: %s [ -h | --help ]/n", argv[0]);
/* ... print usage ... */
return EXIT_SUCCESS;
}
y esto es
razonable
y aceptable, porque no hay una buena razón para que un proceso ejecute otro proceso sin proporcionar al menos la ruta de comando que se está ejecutando, es decir,
execlp(cmd, cmd, NULL)
lugar de
execlp(cmd, NULL)
.
(Sin embargo, puedo pensar en algunas razones nefastas, como explotar ventanas de carrera de tiempo relacionadas con comandos de tubería o socket: un proceso maligno envía una solicitud maliciosa a través de un socket de dominio Unix establecido, y luego se reemplaza inmediatamente con un comando de víctima autorizado (ejecutar sin ningún argumento, para garantizar un tiempo de inicio mínimo), de modo que cuando el servicio que recibe la solicitud verifique las credenciales de los pares, vea el comando de la víctima, en lugar del proceso maligno original. En mi opinión, es lo mejor para esa víctima comandos para bloquearse duro y rápido (
SIGSEGV
, al desreferenciar un puntero NULL), en lugar de intentar comportarse "bien", dando al proceso maligno una ventana de tiempo más grande).
En otras palabras, si bien es
posible
que un proceso se reemplace por otro, pero sin ningún argumento que
argc
que
argc
sea cero, dicho comportamiento no es razonable, en el sentido estricto de que no hay una razón no nefasta conocida para hacerlo.
Debido a esto, y al hecho de que me encanta hacer la vida difícil para los programadores nefastos e indiferentes y sus programas, personalmente nunca agregaré el control trivial, similar a
static int usage(const char *argv0)
{
/* Print usage using argv0 as if it was argv[0] */
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
if (argc < 1)
return usage("(this)");
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
return usage(argv[0]);
/* argv[0] and argv[1] are non-NULL, argc >= 2 */
excepto si lo solicita alguien con un caso de uso existente en particular en mente. E incluso entonces sospecharía un poco, queriendo verificar el caso de uso primero.
cada vez que desee ejecutar cualquier ejecutable como
./a.out
tendrá un argumento que es el
program name
.
Pero es posible ejecutar un programa con
argc
como
zero
en Linux, ejecutándolo desde otro programa que llama a
execv
con una
empty argument list
.
por ej.
int main() {
char *buf[] = { NULL };
execv("./exe", buf); /* exe is binary which it run with 0 argument */
return 0;
}