Преобразовать неподписанное int в подписанное int C - PullRequest
16 голосов
/ 30 ноября 2011

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

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

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

Ответы [ 8 ]

31 голосов
/ 30 ноября 2011

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

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

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>
5 голосов
/ 14 января 2014

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

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

printf("%d\n", y);
4 голосов
/ 30 ноября 2011

@ Мистика поняла.Короткое замыкание обычно 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.

2 голосов
/ 21 марта 2015

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

    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;
   //......
1 голос
/ 30 ноября 2011

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

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

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

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

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

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

0 голосов
/ 01 марта 2019

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

template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
    return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}
0 голосов
/ 30 ноября 2011

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

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);
0 голосов
/ 30 ноября 2011

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

...