c ++ O3优化在循环时中断工作
c++ O3 optimization breaks working while loop
我有这个简单的代码,可以在 pcm wav 文件中使用 fseek 逐步搜索文件 "data":
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++;
}
代码工作正常,在测试文件中找到数据,读取剩余的数据。由于 "data" 即使是最大的文件也接近开头,因此这段代码对我来说没问题。
但是,当我添加 cpp 标志 -O3 时,代码变得混乱,while 循环永远不会结束。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")
我正在使用 cmake + lldb (osx, clion),如果我使用 GDB 也会发生同样的事情。
可能是什么问题,我该如何解决?
PS。我不是想改进您看到的代码,我是想了解为什么编译器优化会破解这个 while 循环。
PSS。
这是空终止的工作代码:
int seekTo = 0;
char data[5];
rewind ( waveFile );
while (( fseek ( waveFile, seekTo, SEEK_SET ) == 0 )) {
fread ( data, 4, 1, waveFile );
data[ 4 ] = '[=12=]';
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;
}
strcmp 是一个字符串比较函数,比较字符串直到找到 NUL 字符。您正在为字符串使用 char[4] ,因此 NUL 字符没有 space 。这有效的事实是一个意外。
在你的情况下,你最好使用 4 个字节的 memcpy。
因为没有其他人想写答案...当代码在关闭优化的情况下工作但停止在优化的情况下工作时,编译器优化可能会揭示一些未定义的行为。在您的情况下,错误是:
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
适用于:
Compares two null-terminated byte strings lexicographically.
所以要么 data
恰好在某个地方有一个 [=15=]
,并且比较是错误的(因为 data
太短了)。或者它没有,并且您将读取 data
末尾朝向内存中某个随机空字节的方式。因此,编译器可以推断出不可能比较是正确的,并将您的代码优化为:
if (false) { ... }
然后完全删除 if
语句。
也许在未优化的构建中,您碰巧总是在 data
之后立即拥有零内存,而 if
从未被优化过?
一个简单的解决方法是确保 data
以 null 结尾:
char data[5];
data[4] = '[=12=]';
// rest as before
或者将 strcmp
的调用替换为 memcmp
,提供 sizeof(data)
作为附加长度参数。
我有这个简单的代码,可以在 pcm wav 文件中使用 fseek 逐步搜索文件 "data":
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++;
}
代码工作正常,在测试文件中找到数据,读取剩余的数据。由于 "data" 即使是最大的文件也接近开头,因此这段代码对我来说没问题。
但是,当我添加 cpp 标志 -O3 时,代码变得混乱,while 循环永远不会结束。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")
我正在使用 cmake + lldb (osx, clion),如果我使用 GDB 也会发生同样的事情。
可能是什么问题,我该如何解决?
PS。我不是想改进您看到的代码,我是想了解为什么编译器优化会破解这个 while 循环。
PSS。 这是空终止的工作代码:
int seekTo = 0;
char data[5];
rewind ( waveFile );
while (( fseek ( waveFile, seekTo, SEEK_SET ) == 0 )) {
fread ( data, 4, 1, waveFile );
data[ 4 ] = '[=12=]';
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;
}
strcmp 是一个字符串比较函数,比较字符串直到找到 NUL 字符。您正在为字符串使用 char[4] ,因此 NUL 字符没有 space 。这有效的事实是一个意外。
在你的情况下,你最好使用 4 个字节的 memcpy。
因为没有其他人想写答案...当代码在关闭优化的情况下工作但停止在优化的情况下工作时,编译器优化可能会揭示一些未定义的行为。在您的情况下,错误是:
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
适用于:
Compares two null-terminated byte strings lexicographically.
所以要么 data
恰好在某个地方有一个 [=15=]
,并且比较是错误的(因为 data
太短了)。或者它没有,并且您将读取 data
末尾朝向内存中某个随机空字节的方式。因此,编译器可以推断出不可能比较是正确的,并将您的代码优化为:
if (false) { ... }
然后完全删除 if
语句。
也许在未优化的构建中,您碰巧总是在 data
之后立即拥有零内存,而 if
从未被优化过?
一个简单的解决方法是确保 data
以 null 结尾:
char data[5];
data[4] = '[=12=]';
// rest as before
或者将 strcmp
的调用替换为 memcmp
,提供 sizeof(data)
作为附加长度参数。