Имеет ли выражение сдвига C тип без знака? Почему Сплинт предупреждает о сдвиге вправо?
Для следующей программы:
int main(void)
{
int value = 2;
int result = value >> 1U;
return result;
}
... Шина 3.1.2 выдает предупреждение:
splint_test.c: (in function main)
splint_test.c:4:18: Variable result initialized to type unsigned int, expects
int: value >> 1U
To ignore signs in type comparisons use +ignoresigns
Кажется, Splint утверждает, что выражение, в котором целое число со знаком сдвигается вправо, имеет тип целого числа без знака. Однако все, что я могу найти в стандарте ANSI C90, это:
Результатом E1 >> E2
являются E1
-сдвинутые вправо битовые позиции E2
. Если E1
имеет тип без знака или E1
имеет тип со знаком и неотрицательное значение, значение результата является неотъемлемой частью отношения E1
деленного на величину 2, возведенную в степень E2
.
Основной целью этого кода является встроенная система с компилятором в основном C90. Тем не менее, я заинтересован в написании кода, соответствующего стандартам. Я тестировал на GCC и Clang в режиме C99, чтобы restrict
работу.
Мои вопросы:
- Предлагает ли стандарт C какие-либо утверждения относительно типа результата сдвига битов?
- Есть ли компиляторы?
- Если нет, то почему Splint может выдавать это предупреждение?
Ответы
Ответ 1
Нет. Стандарт гласит, что тип сдвига битов - это тип левого операнда, повышенный: 6.5.7p3
... Тип результата - тип повышенного левого операнда....
Ваш инструмент должен быть перепутан, выводя тип с помощью обычного арифметического преобразования, которое применяется к большинству бинарных операторов, но не к <<
и >>
.
Вы также можете проверить тип int, вставив утверждение типа _Generic
-based и заметив, что компиляторы его принимают:
int main(void)
{
int value = 2;
int result = _Generic(value >> 1U, int: value>>1U); //compiles, the type is int
return result;
}
Ответ 2
Это ошибка в Splint. Splint ошибочно предполагает, что тип e1 << e2
- ctype_wider(te1, te2)
. Правильный тип будет просто te1
.
Глючный код начинается здесь с использования того же пути кода для побитовых операторов, как &
, |
и ^
, а также для операторов <<
и >>
.
Фактическая ошибка находится в конце этого кода, что предполагает, что для всех этих побитовых двоичных операторов тип возвращаемого значения - ctype_wider(te1, te2)
.
Я открыл ошибку на трекере проблем Splint GitHub, ссылаясь на этот вопрос.
Ответ 3
Стандарты C99 - C17 говорят:
Целочисленные продвижения выполняются на каждом из операндов. Тип результата - тип повышенного левого операнда.
Поскольку value
является int
оно не требует продвижения, а тип "повышенного левого операнда" - int
, а тип результата <<
такой же.
C89/C90 говорит то же самое, за исключением того, что слово "целое" заменено на "целое".