2011-08-10 26 views
16

Dlaczego mój kompilator (GCC) nie jest niejawnie rzutowany z char** na const char**?Niejawna konwersja z char ** na const char **

Thie następujący kod:

#include <iostream> 

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

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

daje następujący błąd:

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

[Dlaczego otrzymuję błąd podczas konwersji 'Foo **' → 'Foo const **'? (Http://www.parashift.com/c++-faq-lite/const-correctness.html#faq -18.17) – fredoverflow

+0

Nie ma czegoś takiego jak "niejawna obsada". "Cast" to jawny operator, który określa konwersję. Mogą też występować niejawne konwersje. ("obsada" to operator, "konwersja" to operacja.) –

+0

@Keith: Myślę, że terminologia nie stanowi problemu. W końcu mówimy "up-cast", a nie "up-conversion". Albo przynajmniej tak mówię. :-) –

Odpowiedz

16

Taka konwersja pozwoli Ci umieścić const char* do swojej tablicy char*, co byłoby niebezpieczne. W print można zrobić:

thing[0] = "abc"; 

Teraz argv[0] wskazywałoby na sznurku dosłownym, które nie mogą być zmienione, natomiast main spodziewa się, że jest non-const (char*). Tak więc dla bezpieczeństwa typu konwersja ta nie jest dozwolona.

+0

Bardzo ładne wyjaśnienie Nie myślałem o tym w ten sposób, dzięki. Zmiana na 'char * const * thing' działa zgodnie z oczekiwaniami. Jednak także "const char * const * thing" powinno działać, ale nie działa. Byłbym wdzięczny za wszelkie dodatkowe informacje na ten temat. – nert

+0

Tak działa dla C++, ale nie dla C, więc wysłałem nowe pytanie, ponieważ nie mogę znaleźć żadnej odpowiedzi: https://stackoverflow.com/questions/35319842/why-c-doesnt-allow-implicit -conversion-from-char-to-const-char-const-i – nert

6

@Fred Overflow's link to the FAQ to pełna odpowiedź. Ale (przepraszam Marshall) nie jest to najbardziej jednoznaczne wytłumaczenie. Nie wiem, czy moje jest bardziej jasne, ale mam taką nadzieję.


Chodzi o to, czy p jest char* wskaźnik, to może być wykorzystane do modyfikować cokolwiek to wskazującego.

A jeśli można uzyskać wskaźnik pp wskazujący na p, ale z pp typu char const**, następnie można użyć pp przypisać p Adres strony const char.

Dzięki temu można następnie użyć p, aby zmodyfikować const char. Lub, możesz pomyśleć, że możesz. Ale ta const char może być nawet w pamięci tylko do odczytu i hellip;

w postaci kodu:

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

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


Jako praktyczne rozwiązanie do kodu, który nie kompiluje, & 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! 
} 

tylko 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. :-) 
} 

Cheers & HTH.,

+0

Ponieważ ten wątek jest połączony jako duplikaty zarówno ze stanowisk C, jak i C++: zauważ, że ostatnia sztuczka nie działa w C. (Nie ma dobrego powodu, aby nie działa w C, to prawdopodobnie tylko niedopatrzenie ze strony komisji normalizacyjnej). –

+0

@MattMcNabb właśnie * dodał * tag C. Ta odpowiedź była w porządku i kompletna, kiedy ją napisałem. To nie działa dla C, nie działa dla Pascala, nie działa dla Haskella, ani żadnego innego języka, do którego dodaje się znaczniki. –

3

uwaga, że ​​chociaż

void dosmth(const char** thing); 

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

jest zabronione, można i należy robić

void dosmth(const char* const* thing); 

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

Która jest chyba to, czego chciał i tak.Chodzi tutaj o to, że thing odnosi się teraz do tablicy const char*, która sama jest niezmienna, a te, do których odnoszą się wartości char, same są niezmienne. Tak więc, dla "spójrz na to, ale nie zmieniaj tego" scenariusz, const char* const* jest typem do użycia.

Uwaga: użyłem bardziej powszechnego (ale moim zdaniem gorszego) standardu próbowania napisania modyfikatora const, tak jak jest to możliwe. Osobiście polecam pisać char const* const* zamiast const char* const*, ponieważ jest to znacznie bardziej zwięzłe.

+0

Też myślałem, że to powinno działać również, ale gcc chce, żeby pierwsza const nie była tam. W szczególności: 'const char * const * thing' daje błąd, ale' char * const * thing' does not. – nert

+0

Więc działa dla C++, ale nie dla C, więc wysłałem nowe pytanie, ponieważ nie mogę znaleźć żadnej odpowiedzi: https://stackoverflow.com/questions/35319842/why-c-doesnt-allow-implicit -konwersja-z-char-na-const-char-const-and – nert

Powiązane problemy