Этот код дает разные результаты для -O1 и -O2:
/*
Example of a clang optimization bug.
Mark Adler, August 8, 2015.
Using -O0 or -O1 takes a little while and gives the correct result:
47 bits set (4294967296 loops)
Using -O2 or -O3 optimizes out the loop, returning immediately with:
0 bits set (4294967296 loops)
Of course, there weren't really that many loops. The number of loops was
calculated, correctly, by the compiler when optimizing. But it got the
number of bits set wrong.
This is with:
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
*/
#include <stdio.h>
#include <inttypes.h>
/* bit vector of 1<<32 bits, initialized to all zeros */
static uint64_t vec[1 << 26] = {0};
int main(void)
{
/* set 47 of the bits. */
vec[31415927] = UINT64_C(0xb9fe2f2fedf7ebbd);
/* count the set bits */
uint64_t count = 0;
uint64_t loops = 0;
uint32_t x = 0;
do {
if (vec[x >> 6] & ((uint64_t)1 << (x & 0x3f)))
count++;
x++;
loops++;
} while (x);
printf("%" PRIu64 " bits set (%" PRIu64 " loops)\n", count, loops);
return 0;
}
Так это ошибка? Или существует какое-то поведение undefined, что компилятор в пределах своих прав дает разные результаты для?
Насколько я могу судить по стандарту C99, цикл do
для прохождения всех значений uint32_t
действителен, так как приращение наибольшего значения без знака равнозначно, чтобы привести к нулю.
Вычисление с использованием неподписанных операндов никогда не может переполняться, потому что результат, который не может быть представлен полученным целым без знака тип уменьшается по модулю число, которое больше одного наибольшего значение, которое может быть представлено результирующим типом.