2016-05-13 15 views
1

ich diesen einfachen Code haben, der die Datei für „Daten“ Schritt für Schritt in einer Datei pcm wav mit fseek sucht:C++ O3 Optimierung Pausen arbeiten, während Schleife

FILE * waveFile; 
    waveFile = fopen (this->fileLocation.c_str (), "rb"); 

    // ... some other code here between, then ... // 

    int seekTo = 0; 
    bool found = false; 
    char data[4]; 

    rewind (waveFile); 
    while (!found && (fseek (waveFile, seekTo, SEEK_SET) == 0)) { 
    fread (data, sizeof (data), 1, waveFile); 
    if ((std::strcmp (data, "data") == 0) || (std::strcmp (data, "Data") == 0) || (std::strcmp (data, "DATA") == 0)) { 
     found = true; 
     fread (&waveHeader->DATA_SIZE, sizeof (waveHeader->DATA_SIZE), 1, waveFile); 
    } 
    seekTo++; 
    } 

Der Code funktioniert einwandfrei, und auf Testdateien es findet die Daten, liest die restlichen. Da die "Daten" selbst bei den größten Dateien fast am Anfang stehen, ist dieser Code für mich in Ordnung.

Aber, wenn ich die cpp-Flag -O3 hinzufügen, geht Code drunter und drüber, während Schleife endet nie.

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3") 

Ich Cmake + LLDB (osx, Clion) verwendet wird, geschieht gleiche Sache, wenn ich GDB verwenden.

Was kann das Problem sein, wie kann ich das beheben?

PS. Ich versuche nicht, den Code zu verbessern, den Sie sehen, ich versuche zu verstehen, warum Compiler-Optimierung diese While-Schleife hackt.

PSS. Hier ist die Null-terminierten Code arbeiten:

int seekTo = 0; 
    char data[5]; 

    rewind (waveFile); 
    while ((fseek (waveFile, seekTo, SEEK_SET) == 0)) { 
    fread (data, 4, 1, waveFile); 
    data[ 4 ] = '\0'; 

    if ((std::strcmp (data, "data") == 0) || (std::strcmp (data, "Data") == 0) || (std::strcmp (data, "DATA") == 0)) { 
     fread (&waveHeader->DATA_SIZE, sizeof (waveHeader->DATA_SIZE), 1, waveFile); 
     break; 
    } 
    seekTo += 1; 
    } 
+9

'std :: strcmp (Daten," Daten ") == 0" liest außerhalb der Grenzen von 'Daten'. Du vergisst die Null-Beendigung. Vielleicht möchten Sie 'Memcmp' mit der Länge' 4'. –

+1

Sie sollten auch überprüfen, ob "fread" erfolgreich war und brechen Sie die Schleife, wenn es fehlgeschlagen –

+0

@ M.M Ich habe ursprünglich die Größe_t für fread im Code überprüfen und es gibt 0 an irgendeinem Punkt zurück. Aber in jeder Datei habe ich "Daten" drin, und das Dateiende ist erreicht, bevor etwas gefunden wird. Also habe ich die Endeprüfung für das Debugging entfernt. – emrahgunduz

Antwort

4

Da niemand sonst eine Antwort schreiben möchte ... Wenn Code mit deaktivierten Optimierungen arbeitet, aber nicht mehr mit Optimierungen arbeitet, ist es wahrscheinlich ein undefiniertes Verhalten, das durch eine Compiler-Optimierung aufgedeckt wird. In Ihrem Fall, dass Fehler ist:

char data[4]; 
... 
fread (data, sizeof (data), 1, waveFile); 
if ((std::strcmp (data, "data") == 0) || (std::strcmp (data, "Data") == 0) || (std::strcmp (data, "DATA") == 0)) { 

strcmp ist für:

Vergleicht zwei nullterminierte Byte-Strings lexikographisch.

Also entweder data geschieht ein \0 darin irgendwo haben, und der Vergleich ist falsch (weil data zu kurz sein würde). Oder es nicht, und Sie werden weg vom Ende von data auf einige zufällige Null-Byte im Speicher lesen. Als Ergebnis könnte der Compiler ableiten, dass keine Möglichkeit gibt es, dass der Vergleich wahr sein könnte und Ihren Code optimieren in:

if (false) { ... } 

und dann vollständig die if Anweisung löschen.

Vielleicht in der nicht optimierten Build, haben Sie zufällig immer Null Speicher unmittelbar nach data und die if wurde nie optimiert?


Eine einfache Lösung dafür wäre, um sicherzustellen, dass data nullterminierte ist:

char data[5]; 
data[4] = '\0'; 
// rest as before 

Oder Ihre Anrufe von strcmp zu memcmp, ersetzen sizeof(data) als die zusätzliche Länge Argument bereitstellt.

+0

danke für das Verständnis der zugrunde liegenden Frage :) was ich in der Fehlersuche sehen kann, dass char [] -Array bekommt einige zusätzliche Zeichen am Ende und die Größe ist falsch, aber das passiert nicht in anderen Fällen. Das Programm liest jedoch weiterhin die Datei. das war alles was ich brauchte. Ich habe bereits die korrigierte Null-Version, die in -o3 funktioniert. aber ich fragte mich, warum es ohne Optimierungen richtig funktionierte. – emrahgunduz

+0

Es funktionierte nicht korrekt ohne Optimierungen. Es zeigt ein undefiniertes Verhalten sowohl bei der Optimierung als auch bei der Deaktivierung an. Undefiniertes Verhalten kann Dinge beinhalten, wie Dämonen aus der Nase fliegen, einen Rücktrittsbrief an deinen nächsten Boss schicken - aber die gruseligsten von ALLEN können genau das tun, was du wolltest. Was ist das, was Sie mit deaktivierten Optimierungen bekommen? Ohne Optimierungen war es immer noch kaputt, funktionierte aber zufällig und hat möglicherweise irgendwann aufgehört zu arbeiten. –

2

strcmp ist eine String-Vergleichsfunktion der Saiten vergleicht, bis das NUL-Zeichen gefunden wird. Sie verwenden char [4] für Ihre Zeichenfolge, sodass für das NUL-Zeichen kein Platz ist. Die Tatsache, dass das funktionierte, war ein Unfall.

In Ihrem Fall sind Sie wahrscheinlich besser dran mit memcpy für 4 Bytes.