2013-08-16 14 views
12

Während einige unserer Code (C++) Debuggen ich dies gefunden:reinterpret_cast Fremdheit (Comma Separated expression)

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; 
} 

Das Problem mit diesem Code (mit Blick auf den Mangel an Zeiger und Stringlänge überprüft) ist, dass das Schließen Klammer der reinterpret_cast wurde nach length platziert, wenn es nach &buffer[index] hätte sein sollen. Zuerst dachte ich, dass dies ein Problem mit dem Compiler ist (mit VS2013), aber nachdem ich es erfolgreich mit VS2012 und gcc 4.6.3 kompiliert habe, bin ich zu dem Schluss gekommen, dass dies aus irgendeinem Grund erlaubt ist. Der Code wird nicht unter Windows oder Linux ausgeführt, da der length-Parameter als Zeiger verwendet wird.

Also meine Frage ist, warum kompiliert sich das? Wenn ich auf die Dokumentation von reinterpret_cast schaue, kann ich keine Dokumentation finden, die besagt, dass Sie eine kommagetrennte Liste von Werten an sie übergeben können und was sie damit machen wird.

+0

Warum sollte es nicht kompilieren? Sie sagen dem Compiler, dass er eine 'size_t' in eine' const char * 'umwandeln soll, und das tut er. Es muss nicht sinnvoll sein, erlaubt zu werden. – Damon

+0

Beachten Sie, dass das Aktivieren der Warnung einen starken Hinweis auf die Vorgänge gegeben hätte, wie ich in meiner Antwort anhand eines Beispiels mit 'gcc' gezeigt habe. –

Antwort

12

reinterpret_cast akzeptiert eine expression. Was Sie in Klammern haben, ist ein Ausdruck - der "," operator mit zwei Unterausdrücken, der das Ergebnis des letzten Unterausdrucks auswerten wird.

+0

Komma-Operator war die Antwort. Ich hatte das vergessen. Ein kurzer Blick in Abschnitt 5.18 in Stroustrups altem "The Annotated C++ Reference Manual" hat das sehr gut erklärt. Danke für deine schnelle Antwort. – william

4

Es ist die comma operator. Er wertet die Ausdrücke auf beiden Seiten des Kommas aus, gibt aber das Ergebnis des Ausdrucks auf der rechten Seite zurück.

Der Grund, warum der Compiler nicht meckert, ist, weil Sie dem Compiler einfach sagen, dass das Ergebnis des Ausdrucks (vom Typ size_t) wie ein const char* Ausdruck behandelt werden soll. Das ist, was reinterpret_cast tut, erlaubt es das Gießen von fast jeder Art zu fast jedem anderen Typ, egal wie dumm es sein kann.

3
reinterpret_cast <new_type> (expression)   

reinterpret_cast ein expression akzeptieren. Hier haben Sie einen Komma-Operator, der die Ausdrücke auf beiden Seiten auswertet und den rechten Ausdruck zurückgibt.

In der Tat entspricht der Ausdruck (&buffer[index], length)(length) hier.

Einfach zu sehen: http://msdn.microsoft.com/en-us/library/zs06xbxh.aspx oder http://en.wikipedia.org/wiki/Comma_operator für Komma Operator Erklärungen.

Zum Schluss, hier sagen Sie Ihrem Compiler, um eine size_t (Ergebnis des Ausdrucks) zu const char* zu werfen und es kann das tun.

7

Das ist wegen der comma operator in c/C++. Der Code (ein Ausdruck):

(&buffer[index], length) 

entspricht (& Puffer [index] nehmen keine Wirkung):

(length)

so Ihren Code entspricht:

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

Dies ist einer der Gründe, warum es wichtig ist, Warnungen aktiviert zu haben, wahrscheinlich hätte es Ihnen geholfen, dies selbst zu lösen.Mit gcc und läuft mit -Wall, ist dies die Warnung, die ich erhielt:

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

Sie die live example sehen können.

Die Warnung sagt uns, dass wir die comma operator zunächst verwenden diese ein wenig sein kann verwirrend aber reinterpret_cast ist kein Funktionsaufruf, in dem dies ohne Verwendung von Klammern nicht funktionieren würde, wie wir in this contrived example, sondern ein Ausdruck sehen und in Abschnitt 5.2Postfix-Ausdrücke der C++ Standardentwurf der grammer für Postfix-Ausdruck enthält:

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

und wir expression im Argument verwenden können, so 0.123.ist vollkommen gültig.

+1

Ich stimme dir vollkommen zu und normalerweise habe ich die Warnstufe bei -Wall. In diesem Projekt wurde es auf Level 3 in Visual Studio gesetzt und das hat keine Warnung generiert, ich habe es in -Wall geändert, aber es warnoch nicht davor gewarnt. Es scheint also, als ob gcc, zumindest in diesem Fall, Warnungen besser melden kann. – william

+0

@william Ich habe ein 'gcc' Beispiel benutzt, da du erwähnt hast, dass du' gcc 4.6.3' versucht hast und 'gcc' zurück zu mindestens' 4.4.4' warnt auch, 'clang' gibt eine gute Warnung. –

Verwandte Themen