Подтвердить что ты не робот

Когда int передается в короткий и усеченный, как определяется новое значение?

Может ли кто-нибудь уточнить, что происходит, когда целое число передается в short в C? Я использую Raspberry Pi, поэтому я знаю, что int - 32 бита, поэтому short должен быть 16 бит.

Скажем, я использую следующий код C, например:

int x = 0x1248642;
short sx = (short)x;
int y = sx;

Я понял, что x будет усечен, но может кто-нибудь объяснить, как именно? Используются ли сдвиги? Как точно усечено число от 32 бит до 16 бит?

4b9b3361

Ответ 1

В соответствии со стандартом ISO C, когда вы конвертируете целое число в подписанный тип, а значение выходит за пределы целевого типа, результат определяется реализацией. (Или может быть поднят сигнал, определяемый реализацией, но я не знаю каких-либо компиляторов, которые это делают.)

На практике наиболее распространенное поведение заключается в том, что старшие разряды отбрасываются. Таким образом, предполагая, что int - 32 бита, а short - 16 бит, преобразование значения 0x1248642, вероятно, даст бит-шаблон, который выглядит как 0x8642. Предполагая, что для подписанных типов (которые используются почти для всех систем) представление двух дополнений, бит высокого порядка является знаковым битом, поэтому числовое значение результата будет -31166.

int y   =   sx;

Это также подразумевает неявное преобразование, от short до int. Поскольку диапазон int гарантированно покрывает по крайней мере весь диапазон short, значение не изменяется. (Так как в вашем примере значение sx оказывается отрицательным, это изменение представления может включать расширение знака, распространяющее знаковый бит 1 на все 16 старших бит результата).

Как я указал, ни одна из этих деталей не требуется по языковому стандарту. Если вы действительно хотите усечь значения более узкому типу, лучше всего использовать неподписанные типы (которые имеют заданное по языку поведение wraparound) и, возможно, явные операции маскировки, например:

unsigned int x = 0x1248642;
unsigned short sx = x & 0xFFFF;

Если у вас есть 32-разрядное количество, которое вы хотите вставить в 16-битную переменную, первое, что вам нужно сделать, это решить, как вы хотите, чтобы ваш код работал, если значение не подходит. Как только вы это решите, вы можете понять, как писать код C, который делает то, что вы хотите. Иногда усечение происходит именно так, как вы хотите, и в этом случае ваша задача будет легкой, особенно если вы используете неподписанные типы. Иногда значение вне диапазона является ошибкой, и в этом случае вам нужно проверить его и решить, как обрабатывать ошибку. Иногда вам может потребоваться насыщение, а не усечение, поэтому вам нужно написать код, чтобы сделать это.

Знание того, как работают преобразования в C, важно, но если вы начнете с этого вопроса, вы просто можете приблизиться к своей проблеме из-за неправильного направления.

Ответ 2

32-битное значение усекается до 16 бит таким же образом, если бы бабановый хлеб длиной 32 см был бы разрезан, если вы застреваете его в кастрюлю длиной 16 см. Половина из них впишется и все еще будет банановым хлебом, а остальное будет "ушло".

Ответ 3

Усечение происходит в регистры процессора. Они имеют разные размеры: 8/16/32/64 бит. Теперь вы можете представить себе такой регистр, как:

<--rax----------------------------------------------------------------> (64-bit)
                                    <--eax----------------------------> (32-bit)
                                                      <--ax-----------> (16-bit)
                                                      <--ah--> <--al--> (8-bit high & low)
01100011 01100001 01110010 01110010 01111001 00100000 01101111 01101110

x сначала задается 32-битное значение 0x1248642. В памяти * это будет выглядеть так:

-----------------------------
|  01  |  24  |  86  |  42  |
-----------------------------
 31..24 23..16 15..8  7..0       

Теперь компилятор загружает x в регистр. Из него он может просто загрузить наименее значимые 16 бит (а именно, ax) и сохранить их в sx.


* Для простоты энтузиазм не учитывается

Ответ 4

Просто высокие 16 бит обрезаются от целого. Поэтому ваш короткий станет 0x8642, который на самом деле является отрицательным числом -31166.

Ответ 5

Возможно, пусть код говорит сам за себя:

#include <stdio.h>

#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte)  \
   ((byte) & 0x80 ? 1 : 0), \
   ((byte) & 0x40 ? 1 : 0), \
   ((byte) & 0x20 ? 1 : 0), \
   ((byte) & 0x10 ? 1 : 0), \
   ((byte) & 0x08 ? 1 : 0), \
   ((byte) & 0x04 ? 1 : 0), \
   ((byte) & 0x02 ? 1 : 0), \
   ((byte) & 0x01 ? 1 : 0) 

int main()
{
    int x    =   0x1248642;
    short sx = (short) x;
    int y    =   sx;

    printf("%d\n", x);
    printf("%hu\n", sx);
    printf("%d\n", y);

    printf("x: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(x>>24), BYTETOBINARY(x>>16), BYTETOBINARY(x>>8), BYTETOBINARY(x));

    printf("sx: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(y>>8), BYTETOBINARY(y));

    printf("y: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(y>>24), BYTETOBINARY(y>>16), BYTETOBINARY(y>>8), BYTETOBINARY(y));

    return 0;
}

Вывод:

19170882
34370
-31166

x: 00000001 00100100 10000110 01000010
sx: 10000110 01000010
y: 11111111 11111111 10000110 01000010

Как вы можете видеть, intshort дает младшие 16 бит, как и ожидалось.

Отбрасывание short в int дает short с установленными 16 битами. Однако я подозреваю, что это специфичное для реализации поведение и undefined. Вы, по сути, интерпретируете 16 бит памяти как целое число, которое читает 16 дополнительных битов любого мусора (или 1, если компилятор хорош и хочет помочь вам быстрее найти ошибки).

Я думаю, что должно быть безопасно сделать следующее:

int y = 0x0000FFFF & sx;

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

Если кто-то может проверить короткое → int high bit поведение с авторитетной ссылкой, это будет оценено.

Примечание: двоичный макрос, адаптированный из этого ответа.

Ответ 6

sx значение будет таким же, как 2 младших значащих байта x, в этом случае оно будет 0x8642, которое (если оно интерпретируется как 16-разрядное целое число со знаком) дает -31166 в десятичной форме.