Преобразовать unsigned int в подписанный int C

Я пытаюсь преобразовать 65529 из unsigned int в подписанный int. Я пробовал делать такие роли:

unsigned int x = 65529;
int y = (int) x;

Но y все еще возвращает 65529, когда он должен вернуться -7. Почему это?

Ответы

Ответ 1

Кажется, вы ожидаете, что int и unsigned int будут 16-разрядным целым числом. Это, очевидно, не так. Скорее всего, это 32-битное целое число, которое достаточно велико, чтобы избежать ожидаемого переноса.

Обратите внимание на то, что для этого не существует полностью совместимого с C способа, потому что литье между подписанными/неподписанными значениями вне диапазона определяется реализацией. Но это будет работать в большинстве случаев:

unsigned int x = 65529;
int y = (short) x;      //  If short is a 16-bit integer.

или, альтернативно:

unsigned int x = 65529;
int y = (int16_t) x;    //  This is defined in <stdint.h>

Ответ 2

Я знаю, это старый вопрос, но он хороший, так как насчет этого?

unsigned short int x = 65529U;
short int y = *(short int*)&x;

printf("%d\n", y);

Ответ 3

@Mysticial получил его. Короткий, как правило, 16-бит и иллюстрирует ответ:

int main()  
{
    unsigned int x = 65529;
    int y = (int) x;
    printf("%d\n", y);

    unsigned short z = 65529;
    short zz = (short)z;
    printf("%d\n", zz);
}

65529
-7
Press any key to continue . . .


Немного более подробно. Это все о том, как подписанные числа хранятся в памяти. Сделайте поиск для двухкомпонентной нотации более подробно, но вот основные сведения.

Итак, давайте посмотрим на 65529 десятичных знаков. Его можно представить как FFF9h в шестнадцатеричном формате. Мы также можем представить, что в двоичном формате:

11111111 11111001

Когда мы объявляем short zz = 65529;, компилятор интерпретирует 65529 как знаковое значение. В двухзадачной нотации верхний бит означает, что значение знака положительное или отрицательное. В этом случае вы можете видеть, что верхний бит является 1, поэтому он рассматривается как отрицательное число. Вот почему он печатает -7.

При значении unsigned short нам не нужен знак, так как он unsigned. Поэтому, когда мы печатаем его с помощью %d, мы используем все 16 бит, поэтому он интерпретируется как 65529.

Ответ 4

Представление значений 65529u и -7 идентично для 16-битных ints. Только интерпретация бит отличается.

Для больших значений и этих значений вам нужно подписать расширение; один путь с логическими операциями

int y = (int )(x | 0xffff0000u); // assumes 16 to 32 extension, x is > 32767

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

int y = ((int ) (x * 65536u)) / 65536;

Умножьте сдвиги на оставшиеся 16 бит (опять же, предполагая расширение от 16 до 32), а разделитель сдвигается вправо, сохраняя знак.

Ответ 5

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

    byte n = 1; //0000 0001 =  1
    n = ~n + 1; //1111 1110 + 0000 0001 = 1111 1111 = -1

А также, что тип int и unsigned int могут быть разного размера в зависимости от вашего процессора. Когда вы делаете такие вещи, как это:

   #include <stdint.h>
   int8_t ibyte;
   uint8_t ubyte;
   int16_t iword;
   //......

Ответ 6

Вы ожидаете, что ваш тип int имеет ширину 16 бит, и в этом случае вы действительно получите отрицательное значение. Но, скорее всего, это 32 бита в ширину, поэтому подписанный int может отлично отображать 65529. Вы можете проверить это, напечатав sizeof(int).

Ответ 7

Чтобы ответить на вопрос, опубликованный в комментарии выше, попробуйте что-то вроде этого:

unsigned short int x = 65529U;
short int y = (short int)x;

printf("%d\n", y);

или

unsigned short int x = 65529U;
short int y = 0;

memcpy(&y, &x, sizeof(short int);
printf("%d\n", y);