2017-08-05 7 views
0

In unserem großen Erbe app mit g ++ neu zu kompilieren 4.8.2 (32-Bit-std = C++ 98), tauchte eine neue Warnung von einem Teil der Daten Serializer warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]C++ Verweis auf C-String ist möglich?

Der Code ohne Warnung auf g zusammengestellt sagen aus ++ 4.4 .7.

Die Warnung kommt von einer Vorlagenfunktion, die ein "char &" serialisiert, wo die Kommentare sagen, dass es sich um eine Referenz auf eine nullterminierte Zeichenfolge handelt.

Ich bin neu in C++ ... ist nicht const char& ein Verweis auf ein einzelnes Zeichen? Und würde diese Referenz nicht als Startadresse einer C-Null-terminierten Zeichenkette eine Art von Cheat sein?

Ignoriere ich die Warnung oder sonstwie, welche Form (falls vorhanden) für dieses Konstrukt?

//! Implementations of write() for null-terminated strings. 
void write(DvCsr::TName, const char* v, long = NO_INDEX) {writeCStr(v);} 
void write(DvCsr::TName, const u_char* v, long = NO_INDEX) {writeCStr(v);} 
void write(DvCsr::TName, const char& v, long = NO_INDEX) {writeRefCStr(v);} 
void write(DvCsr::TName, const u_char& v, long = NO_INDEX) {writeRefCStr(v);} 

//! Write null-terminated string data types to the stream. 
template <class T> 
void writeCStr(const T* start) 
{ 
    // Find length of the string, not including null terminator, 
    // and size (in bytes), including null terminator. 
    const T* end = start; 
    while (*end++) 
     ; 
    size_t len = end - start; 

    // Add the string to the end of the buffer. 
    mBuffer.reserve(mBuffer.size() + len); 
    std::copy(start, start + len, std::back_inserter(mBuffer)); 
}; 

template <class T> 
void writeRefCStr(const T &start) 
{ 
    writeCStr((unsigned char *)start); 
} 
+1

Gute Faustregel: Warnungen nie ignorieren und immer mit '-pedantic -Wall' kompilieren – Rakete1111

+1

@ Rakete1111 Ich würde' -Wextra' hinzufügen (als Minimum). –

+0

@JesperJuhl In diesem Fall würde ich auch '-pedantic-errors -Werror' hinzufügen: P – Rakete1111

Antwort

0

Das ist das Problem:

// Definition 
void write(DvCsr::TName, const char& v, long = NO_INDEX) {writeRefCStr(v);} 

// Call 
void writeRefCStr(const T &start){ 
    writeCStr((unsigned char *)start); 
} 

Sie verwenden den Wert von start zu schreiben. Stattdessen sollten Sie

writeCStr((unsigned char *) &start); 
           ^

... so, dass Sie mit der Adresse von start zu schreiben.

Referenz ist im Wesentlichen ein unveränderbarer Alias ​​ für ein vorhandenes Objekt. Sie erhalten ihre Adresse nicht, wenn etwas als Referenz übergeben wird. Du machst dich selbst. Sie sollten den Adressenoperator & für Ihre Referenz verwenden.

+0

Das wird den Charakter magisch nicht null-terminiert, obwohl es immer noch ein Problem gibt. – Rakete1111

+0

@ Rakete1111 Nehmen wir an, das OP ruft die Funktion korrekt auf. – iBug

+0

Das ist eine falsche Annahme, weil wir sehen, wie die Funktionen aufgerufen werden (die ersten vier Zeilen ohne Kommentare), und sie werden * nicht * mit einer Zeichenkette aufgerufen. – Rakete1111

0

Wenn Sie mit einer Zeichenfolge arbeiten, müssen Sie einen Puffer mit zwei Zeichen zuweisen, um sicherzustellen, dass sie null-terminiert ist.

void writeRefCStr (const T & Start) { const char tmp [2] = {start, 0}; writeCStr (tmp); // tmp ist das gleiche wie const char * }

1

Ich sehe zwei grundlegende Probleme. Zuerst werfen Sie das einzelne Zeichen auf einen Zeiger, Sie müssen seine Adresse &start nehmen. Zweitens werfen Sie von einem const& auf einen nicht konstanten Zeiger, der undefiniertes Verhalten geben kann.

template <class T> 
void writeRefCStr(const T& start) 
{ 
    // use &start to obtain its address 
    // 
    // use reinterpret_cast so the compiler complains about the 
    // lack of const (and make it a const unsigned char*) 
    // 
    writeCStr(reinterpret_cast<const unsigned char*>(&start)); 
} 

Das so genannte "c-style-cast" aka (unsigned char*) entfernt alle Compiler-Warnungen, so dass es die C++ wirft wie reintrpret_cast bevorzugt.

Verwandte Themen