2016-05-13 6 views
1

ステップバイステップでは、PCMのWAVファイルにfseekを使用しながら作業休憩:C++ O3の最適化、私は「データ」のファイルを検索し、この単純なコードを持っているループ

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

コードが正しく動作し、テストファイルにそれはデータを見つけ、残りを読みます。最大のファイルでさえ "データ"が最初から近いので、このコードは大丈夫です。

しかし、私がcppフラグ-O3を追加すると、ループが終了しないうちに、コードがうまく行きます。私はcmakeの+ lldb(OSX、clion)を使用してい

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

私はGDBを使用した場合、同じことが起こります。

何が問題になる可能性がありますか?これをどのように解決できますか?

PS。私はあなたが見るコードを改善しようとしていない、私はコンパイラの最適化がなぜこのループをハックするのか理解しようとしている。

PSS。

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(data、" data ")== 0'は' data'の境界を読み込みます。あなたはヌル終了について忘れています。おそらく長さ '4'の' memcmp'を使いたいかもしれません。 –

+1

また、 'fread'が成功したかどうかチェックし、失敗した場合はループを中断してください。 –

+0

@ M.M私はもともとfreadのためのsize_tチェックをコード中に持っていて、ある時点で0を返します。しかし、私が持っているすべてのファイルには "データ"があり、何かを見つける前にファイルの終わりに達しています。私はデバッグのための終了チェックを削除しました。 – emrahgunduz

答えて

4

誰も答えを書こうと思っていないので...コードは最適化機能をオフにしているが、最適化機能をオンにすることを止めると、コンパイラの最適化によって明らかになる未定義の可能性があります。あなたのケースではそのバグは次のとおりです。

は、辞書的に2 null終端バイト文字列を比較していますため

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です。

だから、どちらかdataはどこかで\0を持っていることを起こる、と(dataが短すぎることになるので)比較はfalseです。そうでないと、メモリ内のランダムなヌルバイトに向かってdataの終わりを読んでいます。

if (false) { ... } 

、その後、完全にif文をドロップします。その結果、コンパイラはその比較が真であるとにコードを最適化することができ方法はありませんことを推論することができます。

おそらく最適化されていないビルドでは、dataの直後に常にメモリがゼロになり、ifは決して最適化されませんでしたか?

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

をまたは追加の長さの引数としてsizeof(data)を提供し、memcmpstrcmpのあなたの呼び出しを置き換えるために:


このための簡単な修正はdataはnull終端であることを保証することです。

+0

基本的な質問を理解していただきありがとうございます:) 最適化では、デバッグでchar []配列が最後にいくつかの余分な文字を取得し、サイズが間違っていますが、これは他の場合には起こりません。ただし、プログラムは引き続きファイルを読み取ります。 私が必要としているのはそれだけです。私は既にヌルで修正されたバージョンを終了しており、-o3で正常に動作しています。私はなぜそれが最適化せずに正常に動作していたのだろうかと思った。 – emrahgunduz

+0

最適化なしでは正しく動作しませんでした。これは、ANDオフでの最適化の両方で未定義の動作を示します。未定義の行動には、悪魔を鼻から飛ばして、次の上司に辞表を送るなどのことが含まれます。しかし、すべての人の中で最も恐ろしいものは、あなたが望むものをまったく行うことができます。最適化を無効にして取得しているものはどれですか。最適化がなければ、それはまだ壊れていましたが、うまく動作し、いつでも動作を停止している可能性があります。 –

2

のstrcmpはNUL文字が発見されるまで、文字列比較関数は、文字列を比較している:ここでは は、コードを作業終了nullです。文字列にchar [4]を使用しているため、NUL文字のスペースがありません。これが事実だったのは事故だった。

あなたの場合、おそらくmemcpyを4バイト使用する方が良いでしょう。

関連する問題