2013-08-16 12 views
12

Durante il debug alcuni del nostro codice (C++) ho trovato questo:reinterpret_cast stranezza (separati da virgola espressione)

inline std::string BufferToStr(
    const unsigned char* buffer, 
    int index, 
    size_t length) 
{ 
    std::string retValue(reinterpret_cast<const char*>(&buffer[index], length)); 
    return retValue; 
} 

Il problema con questo codice (che domina la mancanza di puntatore e lunghezza della stringa assegni) è che la chiusura parentesi di reinterpret_cast è stata inserita dopo length quando avrebbe dovuto essere dopo &buffer[index]. All'inizio pensavo che questo fosse un problema con il compilatore (usando VS2013) ma dopo averlo compilato con successo usando sia VS2012 che gcc 4.6.3, sono arrivato alla conclusione che questo è per qualche motivo permesso. Il codice non verrà eseguito su Windows o Linux poiché il parametro length viene utilizzato come puntatore.

Quindi la mia domanda è: perché viene compilata? Guardando la documentazione di reinterpret_cast non riesco a trovare alcuna documentazione su di esso dicendo che è possibile passare ad un elenco di valori separati da virgola e che cosa farà con esso.

+0

Perché non dovrebbe essere compilato? Stai dicendo al compilatore di lanciare un 'size_t' in un' const char * ', e lo fa. Non ha bisogno di senso per essere permesso. – Damon

+0

Si noti che l'avviso di attivazione avrebbe dato una forte indicazione di ciò che stava accadendo, come ho mostrato nella mia risposta con un esempio usando 'gcc'. –

risposta

12

reinterpret_cast accetta uno expression. Quello che hai tra parentesi è un'espressione: lo "," operator con due sottoespressioni, che valuterà il risultato dell'ultima sottoespressione.

+0

L'operatore di virgola era la risposta. Mi ero dimenticato di quello. Un rapido sguardo alla sezione 5.18 del vecchio "Manuale di riferimento Annotated C++" di Stroustrup lo ha spiegato abbastanza bene. Grazie per la pronta risposta. – william

4

È il comma operator. Valuta le espressioni su entrambi i lati della virgola, ma restituisce il risultato dell'espressione della mano destra.

Il motivo per cui il compilatore non si lamenta è perché si comunica al compilatore che il risultato dell'espressione (di tipo size_t) deve essere considerato come un'espressione const char*. Questo è ciò che fa reinterpret_cast, consente di eseguire il casting di quasi tutti i tipi in quasi tutti gli altri tipi, indipendentemente da quanto possa essere stupido.

3
reinterpret_cast <new_type> (expression)   

reinterpret_cast accettare un expression. Qui hai un operatore virgola che valuta le espressioni su entrambi i lati e restituisce l'espressione della mano destra.

In realtà, l'espressione (&buffer[index], length) è equivalente a (length) qui.

Basta vedere: http://msdn.microsoft.com/en-us/library/zs06xbxh.aspx o http://en.wikipedia.org/wiki/Comma_operator per spiegazioni operatore virgola.

Per concludere, stai dicendo al tuo compilatore di trasmettere un size_t (risultato dell'espressione) a const char* e può farlo.

7

Ciò è dovuto allo comma operator in c/C++. Il codice (espressione):

(&buffer[index], length) 

equivale a (& tampone [index] fa nessun effetto):

(length)

modo che il codice è equivalente a:

inline std::string BufferToStr(const unsigned char* buffer, int index, size_t length) 
{ 
    std::string retValue(reinterpret_cast<const char*>(length)); 
    return retValue; 
} 
2

Questo è uno dei motivi per cui è importante attivare gli avvisi, probabilmente ti avrebbe aiutato a risolverlo da solo.Utilizzando gcc e funzionante con -Wall, questo è l'avvertimento che ho ricevuto:

warning: left operand of comma operator has no effect [-Wunused-value] 
std::string retValue(reinterpret_cast<const char*>(&buffer[index], length)); 
                   ^

Potete vedere il live example.

L'avvertimento noi che stiamo usando il comma operator in un primo momento dice questo può essere un po 'sconcertante, ma reinterpret_cast non è una chiamata di funzione in cui questo non avrebbe funzionato senza usare le parentesi come possiamo vedere in this contrived example, ma un espressione e nella sezione 5.2Postfix espressioni dello standard C++ progetto la grammatica per postfix-espressione contiene:

postfix-expression: 
    ... 
    reinterpret_cast < type-id > (expression) 
    ... 

e siamo in grado di utilizzare un expression nell'argomento in modo 0.123.è perfettamente valido.

+1

Sono totalmente d'accordo con te su questo e di solito ho il livello di avviso a -Wall. In questo progetto è stato impostato sul livello 3 in Visual Studio e questo non ha generato alcun avviso, l'ho modificato in -Wall ma non ha ancora avvisato di questo. Quindi sembra che gcc, almeno in questo caso, è più bravo a segnalare gli avvertimenti. – william

+0

@william Ho usato un esempio di 'gcc' dato che hai menzionato che hai provato' gcc 4.6.3' e 'gcc' di nuovo almeno a' 4.4.4' avverte anche che 'clang' fornisce un buon avvertimento. –

Problemi correlati