Понимать знак побитовой работы Klocwork - PullRequest
0 голосов
/ 27 февраля 2019

При анализе с помощью klocwork следующая строка

pTxData[index] =  ( UINT8_C(0) << UINT8_C(4) );

выдает ошибку

Операнд побитовой операции имеет тип «знаковый символ» вместо «целое число без знака»

Я уже уменьшил проблему до минимума, удалив все #define, и понятия не имею, почему это может произойти.

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Для тех, кто не знает, UINT8_C - это стандартный макрос C 1) для получения целочисленной константы типа uint_least8_t вместо значения по умолчанию int.

Таким образом UINT8_C(0) эквивалентно (uint_least8_t)0.Это будет маленький целочисленный тип.И как таковой он подлежит целочисленному продвижению 2) при передаче в качестве левого операнда на <<.После повышения он заканчивается как тип int, что эквивалентно простой записи 0.

. Никогда не следует использовать знаковые операнды с побитовыми операторами, поэтому это основная причина сообщения об ошибке.Исправленный код должен выглядеть как 0u << 4.Хотя этот код, конечно, бессмыслен для всего, кроме самодокументируемого кода.(И, конечно, смещение значения 0 всегда безвредно.)

Использование UINT8_C для правого операнда << - нонсенс - этот операнд не участвует ни в каком повышении типа результата.Если вам нужно использовать литералы без знака только для того, чтобы удовлетворить стандарт кодирования, тогда используйте 4u.Примечательно, что в таких стандартах, как MISRA-C, , а не требуется суффикс u в тех случаях, когда вам действительно не нужен тип без знака - это распространенный источник ложных срабатываний инструментов.

Сводка - используйте это:

pTxData[index] =  0u << 4;

Кроме того, Klockwork выдает неверное диагностическое сообщение.Операторы в вашем выражении, вероятно, эквивалентны unsigned char и определенно не signed char, как говорит инструмент.


1) Представлено в C99 7.18.4.1.

2) См. Правила продвижения неявного типа

0 голосов
/ 27 февраля 2019

В большинстве выражений целочисленные типы ранга, меньшие, чем int, преобразуются в int (если int может представлять все значения без потерь) или unsigned int (в противном случае).

Чтобы упростить его, рассмотрим ранг, который соответствует количеству битов в типе, чем больше битов, тем выше ранг (для окончательной обработки термина см. Справочник по языку (например, здесь вы можете начать ))).

И здесь, похоже, дело в том, что тип, возвращаемый UINT8_C() (возможно, unsigned char в скрытой форме), имеет меньший ранг, чем int, и в результате вы получитеТип со знаком.

Теперь, причина предупреждения состоит в том, что смещение целочисленных типов со знаком недостаточно хорошо определено во всех случаях.Сдвиг отрицательных значений влево или переполнение при сдвиге составляет неопределенное поведение , что означает, что программа может вести себя неправильно различными способами, если встречается любое из этих двух условий.(При смещении типов без знака допустимо переполнение, вы получаете усеченное значение).

Кроме того, число смещений не может быть отрицательным.

Однако, если это точный код,предупреждение не нужно, потому что должно быть очевидно, что смещение 0 влево на 4 позиции абсолютно безопасно.Если вы используете переменные вместо констант, компилятор (или инструмент) не всегда сможет вывести безопасность этого сдвига, и в этом случае вам следует обратить внимание на предупреждение и переписать свой код таким образом, чтобы не было нинеопределенное поведение или предупреждение.

...