Усечение int до char - это определено? - PullRequest
5 голосов
/ 04 мая 2011
unsigned char a, b;
b = something();
a = ~b;

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

Меня интересует только последний байт повышенного целого числа - если b было 0x55, мне нужно a, чтобы быть 0xAA.Мой вопрос: говорит ли спецификация C о том, как происходит усечение , или это реализация определена / не определена?Гарантируется ли, что a всегда будет присвоено ожидаемое мной значение или оно может работать неправильно на соответствующей платформе?

Конечно, приведение результата перед назначением отключит статический анализатор, но я хочу знать,если это безопасно, в первую очередь игнорировать это предупреждение.

Ответы [ 5 ]

9 голосов
/ 04 мая 2011

Стандарт C определяет это для беззнаковых типов:

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

В этом случае, если ваш unsigned char равен 8 битам, это означает, что результат будет уменьшен по модулю 256, что означает, что если b было 0x55, a действительно закончится как 0xAA .

Но учтите, что если unsigned char на шире , чем 8 бит (что совершенно законно), вы получите другой результат. Чтобы гарантировать, что в результате вы получите 0xAA, вы можете использовать:

a = ~b & 0xff;

(Поразрядный и должен быть оптимизирован на платформах, где unsigned char равен 8 битам).

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

5 голосов
/ 04 мая 2011

Усечение происходит, как описано в 6.3.1.3/2 C99 Standard

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


Пример для CHAR_BIT == 8,sizeof (unsigned char) == 1, sizeof (int) == 4

Итак, 0x55 преобразуется в int, в 0x00000055, затем отрицается до 0xFFFFFFAA, а

      0xFFFFFFAA
    + 0x00000100 /* UCHAR_MAX + 1 */
    ------------
      0xFFFFFEAA

    ... repeat lots and lots of times ...

      0x000000AA

или, как просто 0xAA, как и следовало ожидать

1 голос
/ 04 мая 2011

Он будет вести себя так, как вы хотите.Это безопасно использовать значение.

0 голосов
/ 04 мая 2011

Этот конкретный пример кода безопасен. Но есть причины предостеречь от слабого использования оператора ~.

Причина этого заключается в том, что ~ для небольших целочисленных переменных является потенциальной ошибкой в ​​более сложных выражениях из-за неявных целочисленных повышений в C. Представьте, что у вас есть выражение типа

a = ~b >> 4;

Он не сместится в нули, как можно было ожидать.

Если ваш статический анализатор настроен на включение MISRA-C, вы, например, получите это предупреждение для каждого оператора ~, потому что MISRA принудительно принудительно приводит результат любой операции над маленькими целочисленными типами к ожидаемому типу unsigned char в этом случае.

0 голосов
/ 04 мая 2011

Давайте возьмем случай с машиной Win32.
Целое число равно 4 байта, и преобразование его в символ приведет к тому же результату, как если бы были удалены 3 оставшихся байта.

При преобразовании символа в символ, не имеет значения, к чему это продвигается.
~b will add 3 bytes at the left change 0s to 1 and then remove... It does not affect your one right byte.

Одна и та же концепция будет применима для разных архитектур (будь то 16-битная или 64-битная машина)

Предполагая, что это будет порядок байтов

...