2011-08-10 51 views
16

¿Por qué mi compilador (GCC) no emite implícitamente de char** a const char**?Conversión implícita de char ** a const char **

Thie siguiente código:

#include <iostream> 

void print(const char** thing) { 
    std::cout << thing[0] << std::endl; 
} 

int main(int argc, char** argv) { 
    print(argv); 
} 

da el siguiente error:

oi.cpp: In function ‘int main(int, char**)’: 
oi.cpp:8:12: error: invalid conversion from ‘char**’ to ‘const char**’ [-fpermissive] 
oi.cpp:3:6: error: initializing argument 1 of ‘void print(const char**)’ [-fpermissive] 
+7

[¿Por qué me aparece un error al convertir un 'Foo **' → 'Foo const **'?] (Http://www.parashift.com/c++faq-lite/const-correctness.html#faq -18.17) – fredoverflow

+0

No existe el "molde implícito". Un 'molde' es un operador explícito que especifica una conversión. También puede haber conversiones implícitas. ("cast" es el operador, "conversión" es la operación). –

+0

@Keith: Creo que la terminología no es un problema. Después de todo, decimos "up-cast" y no "up-conversion". O, al menos, digo eso. :-) –

Respuesta

16

una conversión de este tipo permitiría que coloques una const char* en su gama de char*, lo que sería peligroso. En print que podría hacer:

thing[0] = "abc"; 

Ahora argv[0] podría apuntar a una cadena literal que no puede ser modificado, mientras que main espera que sea no constante (char*). Por lo tanto, para la seguridad del tipo, esta conversión no está permitida.

+0

Muy buena explicación No pensé de esta manera, gracias. Cambiarlo a 'char * const * thing' funciona como se esperaba. Sin embargo, también 'const char * const * thing' debería funcionar, pero no es así. Estaría agradecido por más información sobre eso. – nert

+0

Así que funciona para C++ pero no para C, así que publiqué una nueva pregunta para eso porque no puedo encontrar ninguna respuesta: https://stackoverflow.com/questions/35319842/why-c-doesnt-allow-implicit -conversion-from-char-to-const-char-const-and – nert

6

@Fred Overflow link to the FAQ es una respuesta completa. Pero (lo siento Marshall) no es la explicación más clara. No sé si el mío es más claro, pero espero que sí.


La cosa es, si p es un puntero char*, entonces se puede utilizar para modificar como quiera que se apunta a.

Y si se pudiera obtener un puntero que apunta a ppp, pero con pp de tipo char const**, entonces se podría utilizar para asignar a ppp la dirección de un const char.

Y con eso, podría usar p para modificar el const char. O, pensarías que podrías. Pero ese const char podría estar incluso en la memoria de solo lectura & hellip;

En código:

char const  c = 'a'; 
char*    p = 0; 
char const**  pp = &p;    // Not allowed. :-) 

*pp = &c;  // p now points to c. 
*p = 'b';  // Uh oh. 


como una solución práctica a su código que no se compila, y hellip;

#include <iostream> 

void print(const char** thing) { 
    std::cout << thing[0] << std::endl; 
} 

int main(int argc, char** argv) { 
    print(argv); // Dang, doesn't compile! 
} 

just do & hellip;

#include <iostream> 

void print(char const* const* thing) 
{ 
    std::cout << thing[0] << std::endl; 
} 

int main(int argc, char** argv) 
{ 
    print(argv); // OK. :-) 
} 

Saludos & HTH.,

+0

Dado que este hilo está vinculado como duplicados de publicaciones C y C++: tenga en cuenta que el truco final no funciona en C. (No hay una buena razón para ello no funciona en C, es probable que solo sea un descuido del comité de normas). –

+0

@MattMcNabb acaba de * agregar * la etiqueta C. Esta respuesta fue correcta y completa cuando la escribí. No funciona para C, no funciona para Pascal, no funciona para Haskell ni para ningún otro idioma para el que se agregan etiquetas. –

3

Nota, que si bien está prohibido

void dosmth(const char** thing); 

int main(int argc, char** argv) { 
    dosmth(argv); 

, puede y debe hacer

void dosmth(const char* const* thing); 

int main(int argc, char** argv) { 
    dosmth(argv); 

que es probablemente lo que quería de todos modos.El punto aquí es que thing ahora se refiere a una matriz const char* que a su vez es inmutable y cuyos valores de referencia char son inmutables. Por lo tanto, para un escenario de "mírelo, pero no lo cambie", const char* const* es el tipo de uso.

Nota: Utilicé el estándar más común (pero en mi opinión inferior) de intentar escribir el modificador const lo más izquierdo posible. Personalmente, recomiendo escribir char const* const* en lugar de const char* const*, ya que es mucho más conciso de esa manera.

+0

También pensé que esto debería funcionar también, pero gcc quiere que la primera const no esté allí. Particularmente: 'const char * const * thing' produce un error, pero' char * const * thing' no. – nert

+0

Así que funciona para C++ pero no para C, así que publiqué una nueva pregunta para eso porque no puedo encontrar ninguna respuesta: https://stackoverflow.com/questions/35319842/why-c-doesnt-allow-implicit -conversión-de-char-a-const-char-const-y – nert