Puis-je passer un tableau const char * à execv?

Ceci est le prototype pour execv :

 int execv(const char *path, char *const argv[]); 

Puis-je transmettre un tableau de pointeurs de caractères constants comme deuxième argument?

Cet exemple de programme émet un avertissement lorsque USE_CAST n’est pas défini:

 #include  int main(int argc, char *argv[]) { if (argc > 0) { const char *exe_name = "/bin/echo", *message = "You ran"; const char *exe_args[] = { exe_name, message, argv[0], NULL }; #ifdef USE_CAST execv("/bin/echo", (char **) exe_args); #else execv("/bin/echo", exe_args); #endif } return 0; } 

Lors de la compilation, gcc indique “passer l’argument 2 de” execv “à partir d’un type de pointeur incompatible” si je n’utilise pas le transt.

D’après la documentation POSIX pour execv (à mi-chemin de la section Rationale), il semble que le deuxième argument soit un tableau char *const uniquement pour des raisons de compatibilité avec les versions antérieures:

La déclaration sur les constantes argv[] et envp[] étant incluses, elle est incluse pour expliciter aux futurs rédacteurs de liaisons de langage que ces objects sont complètement constants. … Il est regrettable que la quasortingème colonne ne puisse pas être utilisée …

où la “quasortingème colonne” fait référence à const char* const[] .

Le casting de (char **) sûr à utiliser ici? Devrais-je créer un tableau char * et le transmettre à execv à execv place?

Puis-je transmettre un tableau de pointeurs de caractères constants comme deuxième argument?

Eh bien oui, vous savez déjà que vous pouvez lancer afin de le faire.

D’après la documentation POSIX pour execv (à mi-chemin de la section Rationale), il semble que le deuxième argument soit un tableau char * const uniquement pour des raisons de compatibilité avec les versions antérieures:

Je ne dirais pas cela en ces termes, mais oui, il y a un aspect de compatibilité dans la signature choisie. La section à laquelle vous faites référence explique que C n’a pas de façon totalement satisfaisante d’exprimer le degré de const -ness que POSIX a besoin de execv() pour fournir les arguments. POSIX garantit que la fonction ne modifiera ni les pointeurs dans argv ni les chaînes sur lesquelles ils pointent.

Cela étant le cas, je pense qu’il n’est pas déraisonnable de argv pointeur argv comme vous le souhaitez, bien que je laisse un commentaire dans mon code expliquant pourquoi il est prudent de le faire.

D’autre part, vous devriez simplement laisser le const de votre déclaration de tableau:

 char *exe_name = "echo", *message = "You ran"; char *exe_args[] = { exe_name, message, argv[0], NULL }; 

Ou, dans votre exemple simple, même ceci ferait:

 char *exe_args[] = { "echo", message, argv[0], "You ran", NULL }; 

Les littéraux de chaîne C correspondent à des tableaux de type char , non const char . C’est donc parfaitement légal en ce qui concerne C, même si toute tentative de modification du contenu de ces chaînes peut échouer.

De la troisième main, le C moderne a des littéraux de tableau, vous pouvez même faire ceci:

 execv("/bin/echo", (char *[]) { "echo", "You ran ", argv[0], NULL }); 

Dans ce dernier cas, vous n’avez même pas de casting (la chose qui ressemble à un fait partie de la syntaxe d’un littéral de tableau).

Si vous voulez juste jeter le const , vous ne devriez pas utiliser const pour commencer. La plupart des compilateurs (j’ose dire tous) accepteront le code suivant

 char *exe_name = "/bin/echo"; char *message = "You ran"; char *exe_args[] = { exe_name, message, argv[0], NULL }; execv( exe_args[0], exe_args ); 

Si cela ne vous convient pas suffisamment sur le plan pédagogique, l’autre option est

 char exe_name[] = "/bin/echo"; char message[] = "You ran"; char *exe_args[] = { exe_name, message, argv[0], NULL }; execv( exe_args[0], exe_args ); 

Notez que execv va faire des copies des chaînes (pour créer le tableau argv pour l’exécutable), ainsi, que les chaînes soient réellement const ou non.