Преобразование типов объектов с использованием типа без знака в языке Си - PullRequest
0 голосов
/ 31 августа 2018

Я недавно читал KnR и натолкнулся на утверждение:

"Преобразования типов выражений, включающих значения без знака, сложный "

Чтобы понять это, я написал очень маленький код:

#include<stdio.h>
int main()
{
    signed char x = -1;
    printf("Signed : %d\n",x);
    printf("Unsigned : %d\n",(unsigned)x);
}
  • битовая форма со знаком будет иметь вид: 1000 0001 = -1
  • при преобразовании в беззнаковое значение должно быть 1000 0001 = 129. Но даже после преобразования типа он печатает -1.

Примечание: я использую компилятор gcc.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

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

В этом утверждении:

printf("Signed : %d\n",x);

signed char x автоматически повышается до int. Поскольку x равно -1, новый int также имеет значение -1, а printf печатает «-1».

В этом утверждении:

printf("Unsigned : %d\n",(unsigned)x);

signed char x автоматически повышается до int. Значение по-прежнему -1. Затем приведение преобразует это в unsigned. Правило для преобразования в unsigned состоит в том, что UINT_MAX+1 добавляется или вычитается из значения по мере необходимости, чтобы привести его в диапазон unsigned. В этом случае добавление UINT_MAX+1 к -1 один раз приводит к значению UINT_MAX, которое находится в пределах диапазона. Таким образом, результат преобразования равен UINT_MAX.

Однако это значение unsigned затем передается в printf для печати с преобразованием %d. Это нарушает C 2018 7.21.6.1 9, в котором говорится, что поведение не определено, если типы не совпадают.

Это означает, что реализация C может делать что угодно. В вашем случае, кажется, что произошло:

  • Значение unsigned UINT_MAX представлено всеми одними битами.
  • printf интерпретирует значение "все единичные биты" как int.
  • Ваша реализация использует два дополнения для int типов.
  • В дополнении к двум объект со всеми одним битом представляет -1.
  • Итак printf напечатано «-1».

Если вы использовали этот правильный код вместо:

    printf("Unsigned : %u\n",(unsigned)x);

затем printf выведет значение UINT_MAX, что, вероятно, составляет 4 294 967 295, поэтому printf выведет «4294967295».

0 голосов
/ 31 августа 2018

C11 6.3.1.3, пункт 2:

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

−1 нельзя представить как значение unsigned int, -1 преобразуется в UINT_MAX. Таким образом, -1 становится очень большим положительным целым числом.

Кроме того, используйте %u для unsigned int, в противном случае результат вызывает неопределенное поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...