c large-data-volumes

¿Es posible cambiar argv o debo crear una copia ajustada?



large-data-volumes (8)

¡Algunas bibliotecas hacen esto!

El método de inicialización proporcionado por la biblioteca glut opengl (GlutInit) busca los argumentos relacionados con el glut, y los borra moviendo los elementos subsiguientes en argv hacia adelante (moviendo los punteros, no las cadenas reales) y disminuyendo argc

2.1

glutInit glutInit se utiliza para inicializar la biblioteca GLUT.

Uso

void glutInit (int * argcp, char ** argv);

argcp

Un puntero a la variable argc no modificada del programa desde main. Al regresar, el valor al que apunta argcp se actualizará, porque glutInit extrae cualquier opción de línea de comando destinada a la biblioteca GLUT.

argv

La variable argv no modificada del programa desde main. Al igual que argcp, los datos para argv se actualizarán porque glutInit extrae todas las opciones de línea de comandos comprendidas por la biblioteca GLUT.

Mi aplicación tiene potencialmente una gran cantidad de argumentos aprobados y quiero evitar la memoria de los resultados duplicados de los argumentos en una lista filtrada. Me gustaría filtrarlos en su lugar, pero estoy bastante seguro de que no es recomendable jugar con la matriz argv en sí, o cualquiera de los datos a los que apunta. ¿Alguna sugerencia?


El último borrador de la norma C (N1256) establece que hay dos formas permitidas de la función main :

int main (void); int main (int argc, char* argv[]);

pero el quid es la cláusula "o de alguna otra manera definida por la implementación". Esto me parece una laguna en el estándar lo suficientemente grande como para conducir un semirremolque.

Algunas personas usan específicamente "const char *" para que argv no permita cambios en los argumentos. Si su función principal se define de esa manera, no se le permite cambiar los caracteres a los que apunta argv[] , como lo demuestra el siguiente programa:

pax> cat qq.c #include <stdio.h> int main (int c, const char *v[]) { *v[1] = ''X''; printf ("[%s]/n", v[1]); return 0; } pax> gcc -o qq qq.c qq.c: In function `main'': qq.c:3: error: assignment of read-only location

Sin embargo, si elimina la "const" , funciona bien:

pax> cat qq2.c #include <stdio.h> int main (int c, char *v[]) { *v[1] = ''X''; printf ("[%s]/n", v[1]); return 0; } pax> gcc -o qq2 qq2.c ; ./qq2 [Xello]

Creo que este es también el caso de C ++. El borrador actual establece:

All implementations shall allow both of the following definitions of main: int main(); int main(int argc, char* argv[]);

pero no específicamente no permite otras variantes, por lo que presumiblemente también podría aceptar una versión "const" en C ++ (y, de hecho, g ++ lo hace).

Lo único que debes tener en cuenta es tratar de aumentar el tamaño de cualquiera de los elementos. Los estándares no establecen cómo se almacenan, por lo que la extensión de un argumento puede (probablemente afectará) a otros, u otros datos no relacionados.


El estándar C99 dice esto sobre la modificación de argv (y argc ):

Los parámetros argc y argv y las cadenas señaladas por la matriz argv serán modificables por el programa y conservarán sus últimos valores almacenados entre el inicio del programa y la terminación del programa.


El sistema operativo inserta argv y argc en la pila de aplicaciones antes de ejecutarla, y puede tratarlas como cualquier otra variable de pila.


Empíricamente, funciones como GNU getopt () permutan la lista de argumentos sin causar problemas. Como dice @Tim, siempre que juegues con sensatez, puedes manipular el conjunto de punteros e incluso cadenas individuales. Simplemente no invadir ninguno de los límites de la matriz implícita.


La única vez que diría que manipular directamente argv es una mala idea sería cuando una aplicación cambia su comportamiento en función del contenido de argv [0].

Sin embargo, cambiar el comportamiento de un programa dependiendo de argv [0] es en sí mismo una muy mala idea donde la portabilidad es una preocupación.

Aparte de eso, puede tratarlo igual que lo haría con cualquier otra matriz. Como dijo Jonathan, GNU getopt () permuta la lista de argumentos de forma no destructiva, he visto otras implementaciones de getopt () que van tan lejos como la serialización e incluso el hashing de los argumentos (útil cuando un programa se acerca a ARG_MAX).

Solo ten cuidado con tu puntero aritmético.


La asignación original de argv se deja como una opción de compilador / tiempo de ejecución. Por lo tanto, puede que no sea seguro modificarlo de cualquier manera. Muchos sistemas lo construyen en la pila, por lo que se desasigna automáticamente cuando se devuelve la cuenta principal. Otros lo construyen en el montón, y lo liberan (o no) cuando se devuelve principal.

Es seguro cambiar el valor de un argumento, siempre y cuando no intentes hacerlo más largo (error de saturación del búfer). Es seguro barajar el orden de los argumentos.

Para eliminar los argumentos que has procesado previamente , algo como esto funcionará:

(muchas condiciones de error no comprobadas, "--especial" que no se revisaron primero, etc. Esto es, después de todo, solo una demostración del concepto).

int main(int argc, char** argv) { bool doSpecial = false; // an assumption if (0 == strcmp(argv[1], "--special")) { doSpecial = true; // no longer an assumption // remove the "--special" argument // but do copy the NULL at the end. for(int i=1; i<argc; ++i) argv[i] = argv[i+1]; --argc; } // all normal processing with "--special" removed. // the doSpecial flag is available if wanted. return 0; }

Pero vea esto para una manipulación completa: (la parte de la biblioteca libiberty que se utiliza para manipular vectores de estilo argv)

http://www.opensource.apple.com/source/gcc/gcc-5666.3/libiberty/argv.c

Tiene licencia GNU LGPL.


Una vez que se haya pasado argv al método principal, puede tratarlo como cualquier otro conjunto de C: cámbielo en el lugar que desee, solo tenga en cuenta lo que está haciendo con él. El contenido de la matriz no tiene un efecto en el código de retorno o en la ejecución del programa que no sea lo que hace explícitamente con él en el código. No puedo pensar en ninguna razón por la que no sería "recomendable" tratarlo especialmente.

Por supuesto, aún debe tener cuidado de acceder accidentalmente a la memoria más allá de los límites de argv. La otra cara de ser accesible como una matriz C normal es que también es propenso a acceder a errores como cualquier otra matriz C normal. (¡Gracias a todos los que señalaron esto en comentarios y otras respuestas!)