Преобразование unsigned int в signed int C
Я пытаюсь преобразовать 65529
С unsigned int
подписанного int
. Я попытался сделать такой бросок:
unsigned int x = 65529;
int y = (int) x;
но y
все еще возвращает 65529, когда он должен вернуть -7. Почему так?
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
.
чтобы понять, почему, вам нужно знать, что CPU представляет подписанные числа, используя дополнение двух (возможно, не все, но многие).
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-битных ints. Только интерпретация битов различна.
для больших ints и этих значений вам нужно подписать extend; один из способов-с логическими операциями
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);