Передача от "int" до "unsigned short" после применения побитового оператора "~"
Инструмент статического анализа, который я использую, вызывает предупреждение для этого кода:
uint16 var1 = 1U;
uint16 var2 = ~var1;
Я проверяю правила MISRA C 2004, и я нахожу правило 10.5:
Если побитовые операторы ~ и < применяются к операнду od base type unsigned char или unsigned short, результат должен быть немедленно перенесен в базовый тип операнда.
Хорошо, это не проблема, применяется неявное приведение (я думаю, что "cast" означает неявное или явное приведение). Но правило 10.1 гласит:
Значение выражения целочисленного типа не должно быть неявно преобразовано в другой базовый тип, выражение является сложным.
Предыдущий пример сложной операции: ~ u16a
Я меняю свой код на:
uint16 var1 = 1U;
uint16 var2 = (uint16) ~var1;
И я получаю другое предупреждение: я думаю, что преобразование значения int negative в значение unsigned int небезопасно. Я проверяю стандарт C99 (ISO C99) § 6.3.1.3, но я не понимаю, ясно ли указано преобразование int в unsigned short.
В статье EmbeddedGurus Я читал:
c = (unsigned int) a; /* Since a is positive, this cast is safe */
Мои вопросы:
- Явное преобразование из подписанного int в неподписанное короткое неуказанное поведение?
- Если да, как безопасно использовать оператор дополнения с unsigned short?
Ответы
Ответ 1
Операнды арифметических и побитовых операторов всегда подвергаются стандартным акциям до вычисления значения. Все, что меньше int
, продвигается либо до int
, либо unsigned int
, в зависимости от платформы (т.е. В зависимости от того, может ли int
представлять все значения продвигаемого типа).
На вашей платформе uint16_t
стандартно поддерживается int
, так как ваш int
может представлять все значения a uint16_t
. Затем побитовое отрицание применяется к этому значению int
, что является причиной проблемы.
Чтобы получить детерминированный результат независимо от платформы, преобразуйте значение в unsigned int
самостоятельно:
uint16_t var2 = (uint16_t) ~((unsigned int) var1);
Обратите внимание, что это всегда правильно, так как unsigned int
требуется для представления всех значений a uint16_t
.
Ответ 2
- Явное преобразование из подписанного int в неподписанное короткое неуказанное поведение?
Преобразование из подписанных значений без знака хорошо указано, что это происходит через modulo арифметику, охватывается секцией 6.3.1.3
Целочисленные и беззнаковые целые числа из стандартного проекта C99:
В противном случае, если новый тип без знака, значение преобразуется путем многократного добавления или вычитая одно больше максимального значения, которое может быть представлено в новом типе пока значение не окажется в диапазоне нового типа. 49)
Итак, для вашего случая отрицательное число будет конвертировано путем многократного добавления:
UMAX + 1
к отрицательному результату, пока он не станет диапазоном беззнакового типа, к которому вы конвертируете.
Например, преобразование -1
в неподписанный тип всегда приводит к максимальному значению без знака, поскольку -1 + UMAX + 1
всегда UMAX
.
- Если да, как безопасно использовать оператор дополнения с unsigned short?
Что происходит, когда вы применяете оператор ~
, является то, что значение присваивается в int из-за применения целых рекламных акций к операнду ~
. Что описано в разделе 6.5.3.3
Унарные арифметические операторы, в которых говорится (выделено мной):
целые акции выполняются в операнде, а результат имеет продвинутый тип. Если продвинутый тип является типом без знака, выражение ~ E эквивалентно максимальному значению, представленному в этом тип минус E.
Учитывая последнее предложение в цитируемом параграфе, возможно, приведение к unsigned int сначала приведет к более интуитивным результатам:
uint16 var2 = ~((unsigned int)var1);
и поскольку вам необходимо применить явное преобразование, вы получите следующее:
uint16 var2 = (uint16) ~((unsigned int)var1);