Преобразовать без знака Int в подписанный int c

StackOverflow https://stackoverflow.com/questions/8317295

  •  25-10-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

Кажется, что вы ожидаете 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>

Другие советы

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

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

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

@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 Decimal. Это может быть представлено как FFF9h в шестнадцатеричном. Мы также можем представить это в бинарном виде как:

11111111 11111001

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

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

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

    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;
   //......

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

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

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

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

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

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

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

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

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. Поэтому программа не будет интерпретировать это как значение двух комплемента. Одно предостережение заключается в том, что это потеряет информацию для чисел, которые около максимального типа без знака.

template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
    return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top