c++ unix

const c++



execv() y const-ness (4)

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

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.

Pruebe: const char * args [4];

A menudo uso la función execv () en C ++ pero si algunos de los argumentos están en cadenas de C ++. Me molesta que no pueda hacer esto:

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 mis std :: cadenas a matrices de caracteres usando strdup (), que es un problema.

¿Alguien sabe el motivo de esto?


Las especificaciones de base de Open Group explican por qué esto es: 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 la const_cast -ing el resultado de c_str() .

Citar:

La declaración acerca de que argv[] y envp[] son constantes se incluye para hacer explícito a los futuros escritores de enlaces de lenguaje que estos objetos son completamente constantes. 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 - calificación para los parámetros argv[] y envp[] para las funciones del ejecutor puede parecer la opción natural , dado que estas 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 después de eso son aún más perspicaces. Sin embargo, 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.


Por lo general, he pirateado 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); }

; /


Esta es solo una situación en la que la const de estilo C / C ++ 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 el ejecutivo 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 puedes hacer es tener una constante de C en tiempo de compilación como esta:

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

Esto realmente funcionará con la firma de tipo propuesta 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.