Я работаю с сочетанием C90 и C99 (не могу полностью использовать C99 по причинам, которые лучше не обсуждать, потому что они не хороши для моего кровяного давления и угрожают жизни человека, препятствующего нам перемещать наши кодовой базы в текущее тысячелетие). Тем не менее я собираюсь привести стандарт C99.
У меня есть код, примерно такой же, когда он сгущен до минимального минимума (test.c
):
#include <stdio.h>
unsigned int foo(unsigned int n)
{
unsigned int x, y;
n = n - 264;
x = (n >> 2) + 1;
y = 1U << (x + 2U);
return y;
}
int main(void)
{
printf("%u\n", foo(384));
return 0;
}
Разумеется, значение, переданное в foo()
, может быть больше значения, указанного здесь. Тем не менее 384 - это самое низкое значение, которое вызовет статический анализатор Clang (3.4, скомпилированный из тега release), чтобы направить предупреждение:
$ clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -analyzer-checker=core -internal-isystem /usr/local/include -internal-isystem $HOME/bin/LLVM/bin/../lib/clang/3.4/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -x c test.c
test.c:8:9: warning: The result of the '<<' expression is undefined
y = 1U << (x + 2U);
~~~^~~~~~~~~~~
1 warning generated.
Теперь переходя по строкам один за другим:
// n == 384
n = n - 264; // n := 384 - 264
// n == 120
x = (n >> 2) + 1; // x := (120 div 4) + 1
// x == 31
y = 1U << (x + 2U); // y := 1 << 33
Итак, хорошо, что он выталкивает все значащие биты из целого числа, и из моего понимания следующего (из здесь) это должно дать мне просто нуль:
6.5.7 Операторы побитового сдвига
...
4
Результатом
E1 << E2
являетсяE1
левое смещениеE2
битовых позиций; освобожденные биты заполняются нулями. ЕслиE1
имеет без знака тип, значение результатаE1 × 2^E2
, приведено по модулю еще один чем максимальное значение, представляемое в типе результата. ЕслиE1
имеет подписанный тип и неотрицательное значение, аE1 × 2^E2
представим в тип результата, то это результирующее значение; в противном случае поведение undefined.
Из того, как я это прочитал, результат undefined может произойти только когда-либо, если задействованы подписанные значения. Тем не менее, я позаботился о том, чтобы все значения были неподписанными, даже сделав их явными в литералах.
Я ошибаюсь или статический анализатор Clang чрезмерно ревностен?
Оригинальное воплощение этого кода происходит от реализации Джонатана Беннетта JB01 (версия 1.40a) в С++.