Имеет ли выражение сдвига C тип без знака?Почему Сплинт предупреждает о сдвиге вправо? - PullRequest
17 голосов
/ 14 апреля 2019

Для следующей программы:

int main(void)
{
    int value = 2;
    int result = value >> 1U;
    return result;
}

... Splint 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 работает.

Мои вопросы:

  1. Делает ли стандарт C какие-либо утверждения о типе результатасдвига битов?
  2. Есть ли компиляторы?
  3. Если нет, почему Splint может выдавать это предупреждение?

Ответы [ 3 ]

17 голосов
/ 14 апреля 2019

Это ошибка в Splint. Splint ошибочно предполагает, что тип e1 << e2 равен ctype_wider(te1, te2). Правильный тип будет просто te1.

Код ошибки начинается здесь с использованием того же пути к коду для побитовых операторов, как &, | и ^, а также для операторов << и >> .

Фактическая ошибка находится в конце этого кода , что предполагает, что для всех этих побитовых двоичных операторов тип возвращаемого значения равен ctype_wider(te1, te2).

У меня открыта ошибка в системе отслеживания ошибок Splint's GitHub, ссылающаяся на этот вопрос.

17 голосов
/ 14 апреля 2019

Нет.Стандарт гласит, что тип сдвига битов - это тип повышенного левого операнда: 6.5.7p3

... Тип результата - тип повышенного левогооперанд....

Ваш инструмент должен быть перепутан, выводя тип с обычным арифметическим преобразованием, которое применяется к большинству бинарных операторов, но не к << и >>.

. Вы можететакже убедитесь, что тип int, вставив _Generic на основе тип assert и наблюдая , что компиляторы принимают его :

int main(void)
{
    int value = 2;
    int result = _Generic(value >> 1U, int: value>>1U); //compiles, the type is int
    return result;
}
2 голосов
/ 14 апреля 2019

Стандарты C99 - C17 гласят:

Целочисленные преобразования выполняются для каждого из операндов.Тип результата соответствует типу повышенного левого операнда.

Поскольку value является int, он не требует повышения, а тип "повышенного левого операнда" равен int,и тип результата << такой же.

C89 / C90 говорит то же самое, за исключением того, что слово "целое число" заменено на "целое".

...