2008-10-10 22 views
24

A menudo utilizo la función execv() en C++ pero si algunos de los argumentos están en cadenas de C++. Me molesta que no puedo hacer esto:execv() y const-ness

const char *args[4]; 

args[0] = "/usr/bin/whatever"; 
args[1] = filename.c_str(); 
args[2] = someparameter.c_str(); 
args[3] = 0; 

execv(args[0], args); 

Esto no se compila porque execv() toma char * const argv [] que no es compatible con const char * así que tengo que copiar mi std: : cadenas para matrices de caracteres utilizando strdup() que es un dolor.

¿Alguien sabe el motivo?

+0

Creo que puede usar const_cast con seguridad si está seguro de que el programa que ejecuta no cambia sus argumentos. La implementación de execv() no. – Vanuan

+0

He estado escribiendo envoltorios C++ para cada llamada al sistema que realizo, por lo que la llamada al sistema arroja excepciones en lugar de tener que verificar los valores devueltos. Como parte de eso, acabo de hacer un conjunto de sobrecargas que hacen todo el 'const_cast'ing para mí, así que no tengo que tenerlos esparcidos por todo el código. Necesita definiciones de execve para que esto funcione debido a const/non-const para ambos argumentos. Uno, por supuesto, es la definición del sistema. Los otros son solo funciones en línea que se reenvían a los dados dados los moldes apropiados. – Omnifarious

Respuesta

28

Las especificaciones de la base de grupo abierto explican por qué esto es así: para la compatibilidad con el código C existente. Sin embargo, ni los punteros ni los contenidos de la cuerda en sí mismos están destinados a ser cambiados. Por lo tanto, en este caso, puede salirse con const_cast -con el resultado de c_str().

Quote:

La declaración sobre argv[]envp[] y se presentan como constantes se incluye para hacer explícita a los futuros escritores de enlaces de lenguaje que estos objetos son completamente constante. Debido a una limitación del estándar ISO C, no es posible establecer esa idea en el estándar C. Especificar dos niveles de const - la calificación para los parámetros argv[] y envp[] para las funciones del ejecutivo puede parecer la elección natural, dado que estos las funciones no modifican ni la matriz de punteros ni los caracteres a los que apunta la función, pero esto no permitiría el código correcto existente. En cambio, solo la matriz de punteros se observa como constante.

La tabla y el texto a continuación son aún más perspicaces. Sin embargo, Stack Overflow no permite que se inserten tablas, por lo que la cita anterior debe ser contexto suficiente para buscar el lugar correcto en el documento vinculado.

+0

Voy a aceptar esta respuesta aunque Jonathan's sea similar. Este está redactado mejor en mi opinión. –

+0

¡Gracias! Acabo de agregar un poco indicando que la gente debería seguir leyendo, en el artículo citado; explica la razón de ser aún mejor, y cómo, si no fuera por la compatibilidad, char const * const [] hubiera sido mucho más preferible. –

+0

Wy no solo cambia la declaración usando #ifdef __cplusplus ... – user877329

2

const es una cosa C++ - execv ha tomado argumentos char * desde antes de que existiera C++.

Puede usar const_cast en lugar de copiar, porque execv en realidad no modifica sus argumentos. Puede considerar escribir un contenedor para evitar el tipeo.

En realidad, un problema mayor con su código es que ha declarado una matriz de caracteres en lugar de una matriz de cadenas.

Probar: const char * args [4];

+0

Oh, quise escribir const char *, o lo escribí mal o el desbordamiento de la pila ha mordido mi asterisco. Voy a editar la pregunta. –

+0

execv no aceptará const char * arg [] - al menos no con g ++, pero gracias por la respuesta, consideré el casting a non-const pero no sabía si eso era seguro. –

+0

Un compilador de C le permitirá pasar un const char * a execv, pero emitirá una advertencia. Para un compilador de C++, sin embargo, necesita usar const_cast. –

2

por lo general he hackeado esto con:

#define execve xexecve 
#include <...> 
#include <...> 
#include <...> 
#undef execve 

// in case of c++ 
extern "C" { 
    int execve(const char * filename, char ** argvs, char * const * envp); 
} 

;/

+0

Really nice hack – user877329

+0

Yuk, no es agradable. Es mejor usar los encabezados correctos de tu sistema (para asegurarte de que el tipo de función que el vinculador obtiene es el que esperas, suponiendo que la lib y los encabezados coincidan). Use 'const_cast <>' para hacer esto de forma más limpia, en lugar de anular todo redefiniendo de manera horrible con el preprocesador. –

1

Esto es sólo una situación en la C/C++ const estilo no funciona muy bien. En realidad, el kernel no va a modificar los argumentos pasados ​​a exec(). Solo va a copiarlos cuando cree un nuevo proceso. Pero el sistema de tipos no es lo suficientemente expresivo como para tratarlo realmente bien.

Mucha gente en esta página propone hacer que exec tome "char **" o "const char * const []". Pero ninguno de esos realmente funciona para tu ejemplo original. "char **" significa que todo es mutable (ciertamente no es cierto para la constante de cadena "/ usr/bin/whatever"). "const char * const []" significa que nada es mutable.Pero entonces no puede asignar ningún valor a los elementos de la matriz, ya que la matriz en sí misma es const.

lo mejor que podría hacer es tener una constante C de tiempo de compilación como esta:

const char * const args[] = { 
    "/usr/bin/whatever", 
    filename.c_str(), 
    someparameter.c_str(), 
    0}; 

Esto realmente trabajar con la firma de tipo propuesto de "const char * const []". Pero, ¿y si necesitas una cantidad variable de argumentos? Entonces no puede tener una constante en tiempo de compilación, pero necesita una matriz mutable. Entonces has vuelto a las cosas tontas. Esa es la verdadera razón por la cual la firma de tipo del ejecutivo toma "const char **" para los argumentos.

Por cierto, los problemas son los mismos en C++. No puede pasar un std :: vector < std :: string> a una función que necesita un std :: vector < const std :: string>. Tienes que encasillar o copiar todo el std :: vector.

Cuestiones relacionadas