gpt4 book ai didi

c++ - 添加调试输出时循环结果不同(Heisenbug?)

转载 作者:行者123 更新时间:2023-11-28 04:15:25 25 4
gpt4 key购买 nike

如果我在循环中添加调试输出,我有一个行为不同的循环。我想知道这是否是一个编译器错误,或者我是否错误地依赖了一些未定义的 C++ 行为。

循环从 uint64_t 数组中读取整数,将它们存储在临时数组中,然后对条目求和。由于我拥有的数据,我希望总和大于 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)问题消失了。

最佳答案

在 C++(和 C)中,将 k 位整数沿任何方向移动超过 k-1 位是未定义的。

因此,当 j >= 8 时,(overflow[index + j/8] >> (8 * j)) 未定义,这可以(显然)在你的两个循环中导致非常不同的行为。

我认为这应该会产生预期的结果:

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

关于c++ - 添加调试输出时循环结果不同(Heisenbug?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56748305/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com