Почему redlib определяет INT8_MIN как (-0x80), а не как (-0x7F) или (-INT8_MAX — 1)

#c #misra

#c #мисра

Вопрос:

Как следует из названия, REDLIB определяет INT8_MIN как (-0x80). Это выдает предупреждения при использовании QAC для проверки совместимости с MISRA-C: (то же самое касается INT16 и INT32, которые равны -0x8000 и -0x80000000 соответственно)

 Msg(4:1281) Integer literal constant is of an unsigned type but does not include a "U" suffix.
MISRA-C:2004 Rule 10.6; REFERENCE - ISO:C90-6.1.3.2 (Integer Constants)

Msg(4:3101) Unary '-' applied to an operand of type unsigned int or unsigned long gives an unsigned result.
MISRA-C:2004 Rule 12.9; REFERENCE - ISO:C90-6.3.3.3 Unary Arithmetic Operators - Semantics

Msg(4:2850) Constant: Implicit conversion to a signed integer type of insufficient size.
MISRA-C:2004 Rule 3.1; REFERENCE - ISO:C90-6.2.1.2 Conversions (to Signed Integers)
  

Комментарии:

1. Потому что другие значения были бы неправильными. Вы могли бы «исправить» предупреждение, сохранив правильное значение с помощью некоторого приведения. Но, по-видимому, разработчики redlib не беспокоятся о Misra.

2. @undur_gongor На самом деле нет никакого разумного способа «исцелить» что-либо здесь, не переписывая код. -65536 вместо -0x8000 было бы совместимо с MISRA. Так было бы -(int16_t)0x8000 , хотя такая строка не имеет никакого смысла.

3. @Lundin (int16_t)0x8000 — это преобразование вне диапазона (вызывающее поведение, определяемое реализацией)

Ответ №1:

В стандарте C (C11 6.4.4.1) есть тонкое правило о целочисленных литералах («целочисленные константы»), в котором говорится, что если вы пишете простой целочисленный литерал, такой как 70000 без какого-либо суффикса U или L , тип литерала определяется следующим образом:

  • Если литерал достаточно велик, чтобы его можно было сохранить в int, то он имеет тип int.
  • В противном случае, если литерал достаточно велик для хранения в long , то он имеет тип long.
  • (В противном случае в случае C99 / C11 литерал имеет тип long long).

Таким образом, 70000 в 16-разрядной системе тип long был бы.

Но когда вы пишете шестнадцатеричный целочисленный литерал (или восьмеричный), применяются другие правила. Вместо этого компилятор проверяет в этом порядке:

 int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
  

Итак, когда вы пишете 0x8000 в системе, где int равен 16 битам, компилятор проверяет: может ли он поместиться внутри int? Нет. Может ли он поместиться внутри unsigned int? ДА. Следовательно, тип 0x8000 является unsigned int и аналогично 0x80000000 имеет тип unsigned long.

Вот почему вы получаете ошибки MISRA для 0x8000 и 0x80000000 , потому что просто не имеет смысла применять унарный - для неподписанного типа. Так что библиотека не соответствует MISRA-C.

Однако целочисленный литерал 0x80 всегда имеет тип int в любой системе. Если вы получаете ошибку MISRA в этой строке, ваш инструмент статического анализа не работает для этого правила. Отправьте отчет об ошибке в PRQA.

Комментарии:

1. Наш текущий процессор — 32-разрядная версия ARM NXP, поэтому наш базовый тип всегда равен 32 битам, а не 16 битам,?

2. @Daantimmerесли INT16 определено как -0x8000 , вы либо используете 16-разрядный компилятор, либо ваш компилятор действительно странный. Здравомыслящие компиляторы определяют short как 16 бит, а int — как ширину шины данных для данного процессора. Но, конечно, C также допускает безумные реализации. Я бы посоветовал использовать нормальный компилятор…

3.Используемый компилятор — это arm-none-eabi-gcc от GCC, поставляемый с LPCXpresso от NXP. stdint.h определяет: #define INT8_MIN (-0x80) #define INT16_MIN (-0x8000) #define INT32_MIN (-0x80000000) и typedefs как: typedef signed char int8_t; typedef short int16_t; typedef int int32_t; Я думаю, это вполне вменяемый компилятор 🙂

4. @Daantimmerмм, я, наверное, просто перепутал INT16_MIN с INT_MIN. Тем не менее, это делает оба 0x80 и 0x8000 int, и анализатор не должен жаловаться на них.

5. @DaanTimmer -0x80000000 просто неправильно там. Отправьте отчет об ошибке! Это должно быть (-0x7FFFFFFF - 1) или эквивалентно. Другие определения в порядке. Кстати, отредактируйте эту информацию в своем вопросе.