2016-07-11 9 views
3

ich auf dem unten Stück Code arbeite und wenn ich diesen Code bin Ausführung, ich bin eine std::bad_alloc Ausnahme bekommen:Warum bad_alloc() Ausnahme bei size_t geworfen

int _tmain(int argc, _TCHAR* argv[]) 
{ 
FILE * pFile; 

size_t state; 
pFile = fopen("C:\\shared.tmp", "rb"); 
if (pFile != NULL) 
{ 
    size_t rt = fread(&state, sizeof(int), 1, pFile); 
    char *string = NULL; 
    string= new char[state + 1]; 
    fclose(pFile); 
} 
return 0; 
} 

Diese unterhalb der Linie verursacht Ausnahme geworfen werden:

string = new char[state + 1]; 

Warum das passiert und wie kann ich das beheben?

+0

Können Sie den Status vor der Zuweisung drucken und das Ergebnis veröffentlichen? –

+0

Ein Debugger, ein Breakpoint und ein Watch-Fenster werden Ihnen wahrscheinlich sagen, wie groß das Ding ist, das Sie zuzuteilen versuchen. Meine Kristallkugel sagt mir, dass deine Größe in einer Form gespeichert ist, die nicht mit einer 'size_t' übereinstimmt, aber du behandelst sie dennoch als eine, insbesondere weil du die Größe eines' int' liest und darin speicherst eine 'size_t, die auf deiner Plattform wahrscheinlich 32bit und 64bit sind. Autsch. – WhozCraig

+0

Ich wäre auch besorgt über Endianness, da dieser Code direkt in die interne Darstellung des Integraltyps liest, anstatt es aus Bytes zu konstruieren. Das OP könnte denken, dass er eine Ganzzahl mit dem Wert "0x000000FF" liest, aber stattdessen "0xFF0000000" erhält! – Hurkyl

Antwort

7

Sie vorbei die Adresse eines nicht initialisierten 64-Bit (8 Byte, auf moderne 64-Bit-Systeme) Variable, state und sagen freadsizeof(int) (32 Bit, 4 Bytes auf den gleichen Systemen) zu lesen Bytes aus die Datei in diese Variable.

Dadurch werden 4 Bytes der Variablen mit dem gelesenen Wert überschrieben, die anderen 4 jedoch nicht initialisiert. Welche 4 Bytes überschrieben werden, hängt von der Architektur ab (der geringste Wert auf Intel-CPUs, die wichtigste auf Big-Endian-konfigurierten ARMs), aber das Ergebnis wird höchstwahrscheinlich Müll sein, da 4 Bytes nicht initialisiert wurden und alles enthalten könnten .

In Ihrem Fall sind sie höchstwahrscheinlich die höchstwertigen Bytes und enthalten mindestens ein Bit ungleich Null, was bedeutet, dass Sie dann versuchen, weit mehr als 4 GB Speicher zuzuweisen, den Sie nicht haben.

Die Lösung ist state ein std::uint32_t zu machen (da Sie anscheinend erwarten, dass die Datei 4 Bytes enthalten eine ganze Zahl ohne Vorzeichen darstellt, vergessen Sie nicht <cstdint> enthalten) sowie passieren sizeof(std::uint32_t), und im allgemeinen sicher, dass für jeden fread und ähnlicher Aufruf, bei dem Sie einen Zeiger und eine Größe übergeben, stellen Sie sicher, dass die Sache, auf die der Zeiger zeigt, genau die Größe hat, die Sie weitergeben. Das Übergeben eines size_t* und sizeof(int) erfüllt diese Anforderungen auf 64-Bit-Systemen nicht, und da die Größe der Basistypen von C++ nicht garantiert ist, möchten Sie sie im Allgemeinen nicht für binäre E/A verwenden.

+0

ich versuchte mit std :: uint32_t, aber ich bekomme immer noch die gleichen bad_alloc() Fehler. Bitte beachten Sie den Zustandswert nach dem Aufruf von fread - "3435973238" (Dies ist mit size_t). Mit std :: uint32 kommt es dann höher. Mein Problem war eigentlich, dass meine Variable "state" von der Funktion fread() nicht initialisiert wird. –

0

Sie sollten entscheiden, was die maximale Anzahl der Zeichen, die Sie zuweisen möchten, ist und Fehler aus, wenn state größer als das ist. Fast sicher ist es.

1

Es gibt verschiedene Dinge, die Sie in Ihrem C verbessern könnten ++ Code, aber es gibt eine Reihe von Gründen, warum Sie mit diesem Verhalten am Ende:

Zuerst wurde die Variable state ist vom Typ size_t, aber Ihre Code versucht, seinen Wert mit fread(&state, sizeof(int), 1, pFile); zu initialisieren. Jetzt, wenn sizeof(state) != sizeof(int) dann haben Sie undefiniertes Verhalten. Wenn sizeof(state) < sizeof(int), dann überschreibt die fread-Anweisung in der Regel einige willkürliche Speicher nach dem Speicher für die Variable state. Dies führt zu undefiniertem Verhalten (z. B. kann state einen zufälligen großen Wert haben und die Zuweisung schlägt fehl).

Zweitens, wenn sizeof(state) > sizeof(int), werden dann nur teilweise state initialisiert, und sein tatsächlicher Wert hängt sowohl von dem initialisiert (durch fread) und die nicht initialisierten Bits. Daher kann der Wert eine große Zahl sein und die Zuweisung kann fehlschlagen.

Drittens, wenn die sizeof(state) == sizeof(int) dann könnte es nur sein, dass der Wert gelesen zu groß ist, und die Zuweisung einfach scheitert, weil Sie nicht genügend Arbeitsspeicher haben.

Viertens, der Wert, den Sie aus der Datei lesen, könnte eine andere Kodierung oder Endiannität haben.Wenn beispielsweise der Wert in der Datei im Big-Endian-Format geschrieben wurde, aber auf einer Little-Endian-CPU fread ist, kann dies dazu führen, dass die Bytes falsch ausgetauscht werden. Möglicherweise müssen Sie die Bytes austauschen, bevor Sie den gelesenen Wert verwenden.

schlage ich Sie stattdessen einen feste Breite von Integer-Typ <cstdint> (oder <stdint.h> für Pre-C++ 11), wie beispielsweise für variable std::uint64_tstate, liest den Wert mit fread(&state, sizeof(state), 1, pFile); und dann byte-swap state wenn die Die Endianität Ihrer CPU stimmt nicht mit der Endianz des in der Datei gespeicherten Werts überein.

Verwandte Themen