Perché la conversione dalla costante di stringa a 'char *' è valida in C ma non valida in C ++


163

Lo standard C ++ 11 (ISO / IEC 14882: 2011) dice in § C.1.1:

char* p = "abc"; // valid in C, invalid in C++

Per il C ++ è OK come puntatore a un String Literal è dannoso poiché qualsiasi tentativo di modificarlo porta a un arresto anomalo. Ma perché è valido in C?

Il C ++ 11 dice anche:

char* p = (char*)"abc"; // OK: cast added

Ciò significa che se un cast viene aggiunto alla prima istruzione diventa valido.

Perché il casting rende valida la seconda istruzione in C ++ e in cosa differisce dalla prima? Non è ancora dannoso? Se è così, perché lo standard ha detto che è OK?


3
C ++ 11 non consente il primo. Non ho idea del perché C abbia char[]in primo luogo reso letterale il tipo di stringa . Il secondo è const_castsotto mentite spoglie.
chris,

4
C'è semplicemente troppo codice C legacy che si spezzerebbe se questa regola venisse modificata.
Paul R,

1
si prega di citare il testo in cui lo standard dice che il secondo è OK.
Nawaz,

13
Il linguaggio C aveva letterali stringa prima di allora const, quindi necessariamente non lo erano const.
Casey,

2
C e C ++ ti consentono di trasmettere da quasi tutti i tipi a un altro tipo. Ciò non significa che questi cast siano significativi e sicuri.
Siyuan Ren,

Risposte:


207

Fino a C ++ 03, il tuo primo esempio era valido, ma utilizzava una conversione implicita deprecata: una stringa letterale dovrebbe essere trattata come di tipo char const *, poiché non puoi modificarne il contenuto (senza causare un comportamento indefinito).

A partire da C ++ 11, la conversione implicita che era stata deprecata è stata ufficialmente rimossa, quindi il codice che dipende da essa (come il tuo primo esempio) non dovrebbe più essere compilato.

Hai notato un modo per consentire la compilazione del codice: sebbene la conversione implicita sia stata rimossa, una conversione esplicita funziona ancora, quindi puoi aggiungere un cast. Vorrei non , tuttavia, considerare questo "fissare" il codice.

La corretta correzione del codice richiede la modifica del tipo di puntatore nel tipo corretto:

char const *p = "abc"; // valid and safe in either C or C++.

Per quanto riguarda il motivo per cui era consentito in C ++ (ed è ancora in C): semplicemente perché c'è un sacco di codice esistente che dipende da quella conversione implicita, e apparentemente infrangere quel codice (almeno senza qualche avviso ufficiale) sembrava ai comitati standard come una cattiva idea.


8
@rullof: è abbastanza pericoloso che non offre alcuna flessibilità significativa, almeno per il codice che si preoccupa (affatto) della portabilità. Scrivere su una stringa letterale in genere comporta l'interruzione del programma su un sistema operativo moderno, quindi consentire al codice di (provare a) scrivere lì non aggiunge alcuna flessibilità significativa.
Jerry Coffin,

3
Il frammento di codice dato in questa risposta char const *p = "abc";è "valido e sicuro in entrambi C e C ++", non è "valido e sicuro in entrambi i C o C ++".
Daniel Le

4
@DanielLe entrambe queste frasi hanno lo stesso significato
Caleth,

3
Oh mio Signore! [Inserire saldamente la lingua nella guancia] Scusa, ma "o" è il termine corretto qui. Il codice può essere compilato come C o come C ++, ma non può essere compilato contemporaneamente come C e C ++. Puoi scegliere uno dei due, ma devi fare una scelta. Non puoi averli entrambi in una volta. [riprendere il normale funzionamento della lingua].
Jerry Coffin,

2
No, entrambi / ed è la formulazione più chiara e corretta qui. O capita anche di trasmettere il giusto significato, ma tecnicamente non è così chiaro. O da solo è irrefutabilmente sbagliato ( A o B non è uguale a A e B ).
Apollys sostiene Monica il

15

È valido in C per motivi storici. C tradizionalmente specificava che il tipo di stringa letterale era char *piuttosto che const char *, sebbene lo qualificasse dicendo che in realtà non ti era permesso modificarlo.

Quando usi un cast, stai essenzialmente dicendo al compilatore che conosci meglio delle regole di corrispondenza del tipo predefinito e rende l'assegnazione OK.


3
Era un char[N]e fu cambiato in const char[N]. Ha informazioni sulle dimensioni ad esso allegate.
chris,

1
In C il tipo di stringa è letterale char[N]ma non è per char*es."abc"char[4]
Grijesh Chauhan

2

Puoi anche usare strdup :

char* p = strdup("abc");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.