2014-10-06 2 views
11

инструмента статического анализа я использую поднимает предупреждение для этого кода:Cast от «Int» на «неподписанный короткий» после применения оператора побитового «~»

uint16 var1 = 1U; 
uint16 var2 = ~var1; 

я проверяю MISRA C правило 2004 и я нахожу 10.5 правила :

Если битовые операторы и ~ < < применяются к операндом од базового типа символ без знака или без знака короткого, результат должен быть немедленно отбрасываемой к базовому типу из операнда.

Хорошо, это не проблема, применяется неявное приведение (я думаю, что «приведение» означает неявное или явное приведение). Но правило 10.1 гласит:

Значение выражения целочисленного типа не должно быть неявно преобразовано в другой базовый тип, выражение является сложным.

предыдущий пример сложной операции являются: ~ u16a

я изменить мой код:

uint16 var1 = 1U; 
uint16 var2 = (uint16) ~var1; 

И я получаю еще одно предупреждение: Я думаю, что преобразование Int отрицательное значение беззнаковое значение INT не безопасно. Я проверяю стандарт C99 (ISO C99) § 6.3.1.3, но я не понимаю, являются ли четкие преобразования int - неподписанным коротким.

В EmbeddedGurus article Я читаю:

c = (unsigned int) a; /* Since a is positive, this cast is safe */ 

Мои вопросы:

  1. Есть явное преобразование из подписанную INT к беззнаковое короткое неопределенное поведение?
  2. Если да, то как использовать оператор дополнения с unsigned short безопасным способом?
+0

[здесь] (http://stackoverflow.com/questions/25989343/how-is-shift-operator-evaluated-in-c) - некоторые полезные ответы, объясняющие числовое продвижение – chouaib

ответ

13

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

На вашей платформе, uint16_t стандартен раскрученный в int, так как ваш int может представлять все значения в uint16_t. Затем побитовое отрицание применяется к значению int, что является причиной проблемы.

Чтобы получить детерминированный результат независимо от платформы, преобразовать значение к unsigned int себя:

uint16_t var2 = (uint16_t) ~((unsigned int) var1); 

Обратите внимание, что это всегда правильно, так как unsigned int требуется, чтобы иметь возможность представлять все значения а uint16_t.

+0

. Какой бы правильный способ написать код, если тип, о котором идет речь, был 'int32_t', а не' int16_t', поскольку на некоторых компиляторах 'long' может быть 64 бит, а на других 'int' будет 16? – supercat

+0

'int16_t' всегда можно повысить до' int', если на самом деле это нужно для продвижения, поэтому вам не нужно ничего писать. (Тем не менее, побитовые операции с целыми знаками, как правило, не рекомендуется.) –

+0

Следовательно, мой (предполагаемый) вопрос о том, как следует писать код, если тип был 'uint32_t', а не' uint16_t'. Отбрасывание на 'unsigned int' завершится неудачей на платформах, где' unsigned int' - 16 бит, а приведение к 'unsigned long' может привести к усечению значения, если этот тип равен 64 битам. IMHO, для того чтобы C был достойным языком для написания переносимого кода, он должен включать неподписанные типы фиксированного размера *, которые не будут способствовать *. – supercat

4
  1. Иметь явное преобразование из подписанных межд в беззнаковое короткое неустановленное поведение?

Переход от подписан беззнаковых значений хорошо указано, что происходит с помощью арифметических операций по модулю охватывается разделе 6.3.1.3Подписанные и неподписанные целых из проекта стандарта C99:

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

Так что для вашего случая отрицательного число будет преобразовано путем многократного добавления:

UMAX + 1 

к отрицательному результату, пока он не является диапазоном без знака типа вы превращающие в.

Например, преобразование -1 в неподписанный тип всегда приводит к максимальному значению без знака, так как -1 + UMAX + 1 всегда UMAX.

  1. Если да, то как использовать оператор дополнения с unsigned short безопасным способом?

Что происходит, когда вы применяете оператор ~ является то, что значение приносит продвинут на INT из-за целые акции применяются к операнду ~. Что рассматривается в разделе 6.5.3.3Унарные арифметические операторы, которые говорит (курсив мой ):

В целые акции выполняются на операнд, и результат имеет расширенный тип. Если продвинутый тип является типом , выражение ~ E эквивалентно максимальному значению, представляемому в этом типа минус E.

Учитывая последнее предложение в процитированном абзаце, может быть литейным неподписанных INT первый может привести к более интуитивным результаты:

uint16 var2 = ~((unsigned int)var1); 

и так как вы должны применять явное приведение, то вы в конечном итоге с этим:

uint16 var2 = (uint16) ~((unsigned int)var1); 
+0

Проблема в том, что значение '~ 1' может варьироваться в зависимости от представления 'int' (например, -1 в дополнении, -2 в дополнении и т. Д.), Поэтому результат при преобразовании в' unsigned short' также может быть другим. –

+0

@ T.C. Я удалил этот оператор, поскольку вы указали, что он слишком широк. –

Смежные вопросы