¿Es correcto mi entendimiento de cómo funciona este programa en C?
en el siguiente programa:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
char *delivery = "";
int thick = 0;
int count = 0;
char ch;
for (int i = 0; i < argc; i++) {
fprintf(stdout, "Argv[%i] = %s\n", i, argv[i]); /* printing to understand (ptu) */
}
while ((ch = getopt(argc, argv, "d:t")) != -1)
switch (ch) {
case 'd':
fprintf(stdout, "Optind in case 'd': %i\n", optind);
delivery = optarg;
break;
case 't':
fprintf(stdout, "Optind in case 't': %i\n", optind);
thick = 1;
break;
default:
fprintf(stderr, "Unknown option: '%s'\n", optarg);
return 1;
}
fprintf(stdout, "Argc: %i\n", argc); /* ptu */
fprintf(stdout, "Argv: %p\n", argv); /* ptu */
argc -= optind;
argv += optind;
fprintf(stdout, "Optind: %i. Argc after subtraction: %i, Argv after increment: %p\n", optind, argc, argv);
if (thick)
fprintf(stdout, "Thick crust!\n");
if (delivery[0])
fprintf(stdout, "To be delivered %s\n", delivery);
fprintf(stdout, "Ingredients:\n");
for (count = 0; count < argc; count++)
fprintf(stdout, "%s\n", argv[count]);
return 0;
}
Cuando ejecuto el programa anterior con los argumentos que se muestran a continuación, obtengo el siguiente resultado:
[u@h c]$ ./prog -t -d yesterday anchovies goatcheese pepperoni
Argv[0] = ./prog
Argv[1] = -t
Argv[2] = -d
Argv[3] = yesterday
Argv[4] = anchovies
Argv[5] = goatcheese
Argv[6] = pepperoni
Optind in case 't': 2
Optind in case 'd': 4
Argc: 7
Argv: 0x7ffebee8e498
Optind: 4. Argc after subtraction: 3, Argv index: 0x7ffebee8e4b8
Thick crust!
To be delivered yesterday
Ingredients:
anchovies
goatcheese
pepperoni
Me gustaría saber si mi comprensión de lo que sucede bajo el capó es precisa, específicamente para los pasos de análisis de argumentos en el programa. Disculpas por no compartir una reprex más mínima, pero en este caso probablemente no podría. No habría enviado spam a stackoverflow si pudiera mostrarle esto a un amigo que entendiera C. Así que, por favor tengan paciencia conmigo. Aquí va nada:
Principal definido para aceptar parámetros de línea de comandos (cl). Esto requiere dos parámetros:
- entero argc que contendrá el número de parámetros cl incluyendo el nombre del programa, en este caso es 7
- matriz de cadenas (es decir, matriz de punteros de caracteres), cada elemento de los cuales apuntará a la dirección de memoria del primer elemento de cada literal de cadena (almacenado en el bloque de memoria CONSTANT) pasado como un parámetro cl al programa.
para bucle (se explica por sí mismo)
En cada ejecución del bucle while, getopt () analizará la matriz argv [] y asignará el siguiente carácter coincidente de la
optstring "d:t"variable de carácter toch, hasta que se quede sin opciones (sin juego de palabras) que es cuando volverá-1y el control lo hará salir del bucle while.- en cada paso de este tipo
optind(que se inicia en 1 presumiblemente porque argv [0] es el nombre del programa) se incrementará para contener el índice del siguiente elemento que se procesará en argv ... Así que encase 't', optind = <index of "-d" i.e. 2>, y encase 'd', optind = <index of "anchovies" i.e. 4>(esto es porque segetopt()da cuenta desde el ":" después ded"en eloptstringque-dserá seguido por suoptargen la línea de comando, por lo queoptindse incrementa a" 4 "aquí en lugar de ser" 3 ") - después
-ty-d yesterdayse procesangetopt()no puede encontrar cualquier otra cosa enargv[]la que coincide con los elementos en eloptstring; por lo tanto, regresa-1y salimos del ciclo while.optindpermanece establecido en 4 porque getopt no encontró nada más después de '-d' de la cadena de opciones.
- en cada paso de este tipo
Ahora disminuimos
optindel valor "4" deargcpara asegurarnos de que salteamosoption arguments(que ya hemos analizado) a los tresnon-optionargumentos restantes . También incrementoargv-que inicialmente señaló a la posición de memoria deargv[0]decir"./prog"-por<optind * sizeof(char pointer on a 64-bit machine); i.e. 4 * 8>razón por la cual ahora apunta ARGV 32 bytes por delante en la memoria:0x7ffebee8e4b8 - 0x7ffebee8e498 == 0x20. En otras palabras, argv [0] apunta a "anchoas".Luego imprimimos cosas dependiendo de los valores de
thick,deliveryy recorremos los argumentos restantes que no son de opción para imprimirlos también ...
Respuestas
Sí, tu comprensión es correcta.
Ofrecería dos notas:
"String literal" se refiere a una cadena que está realmente definida dentro de su programa, como caracteres entre
""delimitadores. El "bloque CONSTANTE" no es un concepto estándar, pero supongo que te refieres a un bloque de memoria de solo lectura que se carga desde el binario, ya que ahí es donde normalmente residen los literales de cadena. Las cadenas a las queargvapuntan los punteros no son de este tipo; no pueden serlo, porque no se conocen cuando se crea el binario. En cambio, están ubicados en alguna región de memoria no especificada, y puede modificarlos en su lugar si lo desea (aunque es probable que esto confunda su código); por ejemploargv[0][3] = 'x', sería legal. (Estándar C17 5.1.2.2.1 (2)).Algunas personas también pueden encontrar confuso modificar los valores de
argcyargvdentromain, y sugerirían que asigne los valores modificados a algunas otras variables en su lugar:
int remaining_argc = argc - optind;
char **remaining_argv = argv + optind;