如果在循环中添加调试输出,则我的循环的行为会有所不同。我想知道这是否是编译器错误,还是我错误地依赖于某些未定义的C++
行为。
循环从uint64_t
数组中读取整数,将它们存储在temp数组中,然后对各项求和。由于我有数据,我希望总和大于60。
如果它小于60(令人惊讶),我将重试同一循环,这次添加调试输出。我希望得到小于60的结果,但是现在大于60。
uint64_t test[8];
for(int i=0; i<8; i++) {
test[i] = overflow[index + i];
}
int temp[64];
int count2 = 0;
for(int j = 0; j < 64; j++) {
int cj = (int) ((test[j / 8] >> (8 * j)) & 0xff);
count2 += cj;
temp[j] = cj;
}
if (count2 < 60) {
int count3 = 0;
for(int j = 0; j < 64; j++) {
int cj = (int) ((test[j / 8] >> (8 * j)) & 0xff);
temp[j] = cj;
::std::cout << " foo\n";
count3 += cj;
}
::std::cout << "count2 " << count2 << " count3 " << count3 << "\n";
}
示例输出:
foo
...
foo
count2 6 count3 62
循环的方向无关紧要(如果循环从0到63,则结果相同)。只有一个线程。如果我在第二个循环中评论cout,例如“ count2 4 count3 4” (某些原始的意外情况)。一旦在循环中执行任何形式的cout(甚至是“ foo”),我就会再次得到count2!= count3。我试图使第一个循环更复杂(不必要将cj乘以100),但结果相同。
Makefile中的编译器选项:
OPT = -O3 -DNDEBUG -march=native
CXXFLAGS += -fno-strict-aliasing -Wall -std=c++11 $(OPT)
LDFLAGS = -Wall
与LLVM和g ++相同的结果。
"-O2"
(g ++,未尝试LLVM)解决了问题。
答案 0 :(得分:1)
在C ++(和C)中,未定义将k位整数在任何方向上移位超过k-1位。
因此,(overflow[index + j / 8] >> (8 * j))
在j >= 8
时是未定义的,这(显然)会在您的两个循环中引起非常不同的行为。
我认为这应该会产生预期的结果:
int temp[64] = {0};
for(int j = 0; j < 8; j++) {
int cj = (int) ((test[j / 8] >> (8 * j)) & 0xff);
count2 += cj;
temp[j] = cj;
}