c ++ O3优化在循环中中断

时间:2016-05-13 11:29:52

标签: c++ c++11 compiler-optimization fseek

我有这个简单的代码,在pcm wav文件中使用fseek逐步搜索文件中的“数据”:

  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时,代码变得混乱,而循环永远不会完成。

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

我正在使用cmake + lldb(osx,clion),如果我使用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;
  }

2 个答案:

答案 0 :(得分: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适用于:

  

按字典顺序比较两个以null结尾的字节字符串。

因此,data恰好在某个地方有\0,而且比较为假(因为data太短了)。或者它不会,并且您将从data的末尾读取内存中的某个随机空字节。因此,编译器可以推断出无法比较可能是真的并将您的代码优化为:

if (false) { ... }

然后完全删除if语句。

也许在非优化版本中,您在data之后始终没有内存,而if从未优化过?

一个简单的解决方法是确保data以空值终止:

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

或者将strcmp的来电替换为memcmp,并提供sizeof(data)作为额外的长度参数。

答案 1 :(得分:2)

strcmp是一个字符串比较函数,比较字符串直到找到NUL字符。您正在为字符串使用char [4],因此NUL字符没有空格。事实证明这是一次意外事故。

在你的情况下,你可能最好使用memcpy 4个字节。