2016-05-13 63 views
1

我有这个简单的代码,在文件中搜索“数据”步步在PCM WAV文件中使用FSEEK工作:C++ O3优化符while循环

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时,代码变得不合时宜,while循环永远不会结束。

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

我使用cmake + LLDB(OSX,克利翁),如果我用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'的范围。你忘记了空终止。也许你想''memcmp'长度为'4'。 –

+1

你还应该检查'fread'是否成功,如果失败,请打破循环 –

+0

@ M.M我原来在代码中检查了fread的size_t,它在某些时候返回0。但是,在每个文件中都有“数据”,并且在找到任何内容之前都已经达到文件结尾。所以我删除了调试结束检查。 – emrahgunduz

回答

4

因为没有其他人想写一个答案......当代码在优化关闭但是停止对优化进行工作时,它可能是一些未定义的行为,这是由编译器优化揭示的。在你的情况下错误是:

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是太短)。或者它不会,并且您将读取data的结尾,朝向内存中的某个随机空字节。其结果是,编译器可以推断出有没有办法是比较可能是真实和优化你的代码:

if (false) { ... } 

,然后完全放下if声明。

也许在未经过优化的版本中,在dataif从未被优化过后,您碰巧始终没有记忆?


一个简单的办法解决,这将是确保data是空值终止:

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

或取代的strcmp来电memcmp,提供sizeof(data)作为额外的长度参数。

+0

感谢您理解底层问题:) 我在调试中可以看到优化,char []数组在末尾获得一些额外的字符并且大小是错误的,但在其他情况下不会发生这种情况。然而,程序继续读取文件。 这就是我所需要的。我已经有空终止的修正版本,在-o3中正常工作。但我想知道为什么它没有优化就能正常工作。 – emrahgunduz

+0

没有优化,它无法正常工作。它显示未定义的行为,并在AND关闭时进行优化。未定义的行为可能包括让恶魔飞出你的鼻子,向你的下一位老板发送辞职信,但最令人恐惧的是所有可能发生的都是你想做的事情。这是您在禁用优化时所获得的结果。没有优化,它仍然是坏的,但碰巧工作,并可能在任何时候停止工作。 –

2

STRCMP是一个字符串比较函数,直到NUL字符是字符串比较。你正在为你的字符串使用char [4],所以NUL字符没有空间。这个工作的事实是一个意外。

就你而言,你可能最好使用4字节的memcpy。