Преобразование из меньшего типа данных в больший и наоборот

У меня есть этот код C, который пытается сохранить signed short в signed char. signed char диапазон равен [-128,127], а диапазон signed short равен [-32768, 32767].

signed char sChar = SCHAR_MAX;
printf("Signed Char: %d", sChar);

signed short sShort = SHRT_MAX;
printf("\nSigned Short: %d", sShort);

sChar = sShort;
printf("\nSigned Short to Signed Char: %d", sChar);

Вывод:

Signed Char: 127
Signed Short: 32767
Signed Short to Signed Char: -1

Я думаю, это происходит в фоновом режиме.

signed short in bits: 0111       1111   1111  1111 (32767)
signed char in bits: <discarded bits>   1111  1111 (-1)

В основном он копирует все биты справа и отбрасывает оставшиеся. TL; DR Он сокращается, чтобы сохранить в char, поэтому мы теряем информацию.

Вопрос начинается здесь. Приведенная выше информация должна была дать предысторию.

Допустим, я даю signed char -1 и пытаюсь сохранить его в signed short. Значение внутри signed short будет -1. В двоичном формате, если он представлен, это будет:

signed char in bits:              1111  1111 (-1)
signed short in bits: 1111  1111  1111  1111 (32767)

У меня вопрос, как компилятор назначает char для short в фоновом режиме? Это определенно не однозначная копия, как указано выше. Я предполагаю, что он сдвигает биты вправо, а остальные дополняют.

          1111 1111 // Signed Char
1111 1111 0000 0000 // Shifting bits
1111 1111 1111 1111 // Ones' complimenting the right 8 bits 

person Goion    schedule 12.09.2019    source источник
comment
См. Пример кода ассемблера - godbolt.org/z/UT2PSF   -  person OldProgrammer    schedule 12.09.2019
comment
Второй - целочисленное продвижение.   -  person EsmaeelE    schedule 12.09.2019
comment
Подписанное переполнение не определено; однако, исключив компилятор, пытающийся оптимизировать, предполагая, что этого не происходит, вы получите это. На практике это было определено до недавнего времени, поэтому большинство производителей опасаются радикальной поломки.   -  person Joshua    schedule 12.09.2019
comment
Внезапно назначение определяется реализацией Стандарт C11 - Типы 6.2.5 ( p3)   -  person David C. Rankin    schedule 12.09.2019


Ответы (2)


Это не полный и хороший ответ, потому что я хочу спать, но я думаю, что может вам помочь.

Скоро отредактирую.

Код

#include <stdio.h>
#include <limits.h>

#show bits
//https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format

void printbitsc( signed char x)
{
    for(int i=sizeof(x)<<3; i; i--)
        putchar('0'+((x>>(i-1))&1));
}

void printbitss( signed short x)
{
    for(int i=sizeof(x)<<3; i; i--)
        putchar('0'+((x>>(i-1))&1));
}

//https://www.geeksforgeeks.org/little-and-big-endian-mystery/

/* function to show bytes in memory, from location start to start+n*/
void show_mem_rep(char *start, int n)  
{ 
    int i; 
    for (i = 0; i < n; i++) 
         printf(" %.2x", start[i]);
     
    printf("\n");
 
    if (start[0]==0x67)
        printf("little endian\n"); 
    else
        printf("big endian\n"); 
    
} 

int main(int argc, char const *argv[]) {

    int i = 0x01234567; 
    show_mem_rep((char *)&i, sizeof(i)); 
    
    printf("%zu\n",sizeof (signed short));
    printf("%zu\n",sizeof (signed char));

    signed char sChar = SCHAR_MAX;
    printf("Signed Char: %d\n", sChar);
    printbitsc(sChar);

    signed short sShort = SHRT_MAX;
    printf("\nSigned Short: %d\n", sShort);
    printbitss(sShort);

    sChar = sShort;

    printf("\nSigned Short to Signed Char: %d\n", sChar);
    printbitsc(sChar);
  

    signed char ssChar = SCHAR_MAX;
    printf("Signed Char: %d\n", ssChar);
    printbitsc(ssChar);

    signed short ssShort = SHRT_MAX;
    printf("\nSigned Short: %d\n", ssShort);
    printbitss(ssShort);

    ssShort=ssChar;

    printf("\nSigned Short to Signed Char: %d\n", ssShort);
    printbitsc(ssShort);


    return 0;
}

В памяти с прямым порядком байтов данные хранятся в памяти в обратном порядке, т.е. 0x01: 1 значение хранится в памяти: 0x10:1111_0000:240 (изменить порядок единиц и нуля)

Итак, в первом случае мы сталкиваемся со случаем усечения как

ss: 0111_1111_1111_1111 7 F F F

Внутри памяти на самом деле есть: F F F 7

и для

sc: 0111_1111 7 F

В памяти на самом деле есть: F 7

Теперь по назначению первый элемент памяти ss, т.е. FF будет усечен и помещен на 16-битное sc место.

F F -> F 7

Теперь у нас действительно есть в памяти: 1111_1111

позволяет перевести его в удобочитаемое число (я конвертирую из двоичного дополнения в десятичное)

сначала первый означает минус (1: -), теперь мы достигаем: 111_1111 с помощью алгоритма отслеживания конверсии: minus [ not( 111_1111) + 1] = minus[(000_0000)+1] = minus [1] = -1

Наконец мы дошли до -1 по sc переменной.

Во втором случае будет начислена целочисленная акция.

sc: 0111_1111 7 F

Память: F 7

ss: 0111_1111_1111_1111 7 F F F

Память: F F F 7

Мы работаем с памятью, F7 хочет попасть внутрь FFF7, поэтому F7 нужно увеличить до 16-битной длины, добавив лишний 0.

Эти нули добавляются после первого элемента, и F7 меняется на F700.

Теперь вопрос в том, как F700 перейти на место длиной 16 бит.

F700 -> F F F 7

После этого мы сталкиваемся с F700 по переменной длиной 16 бит.

Как мы знаем, F700 на самом деле представляет собой этот битовый шаблон: 0000_0000_0111_1111, когда мы читаем его с помощью обычного printf(), это показывает 007F.

Путем простого преобразования двоичного кода в десятичное 007F равно 127.

Делать

  • Отредактируйте сообщение, чтобы было лучше
person EsmaeelE    schedule 12.09.2019

как компилятор назначает (подписанный) char в фоновом режиме?

Отложите в сторону лежащую в основе битовую механику. значение скопировано.

Это происходит при переходе от одного числового типа к другому.

Если в типе назначения отсутствует значение, результат зависит от типа. С целыми типами подписанными: «новый тип подписан, и значение не может быть представлено в нем; либо результат определяется реализацией, либо возникает сигнал, определяемый реализацией» C11dr §6.3.1.3 3


Если вам необходимо знать, скорее всего, бит знака - это знак расширенный.

person chux - Reinstate Monica    schedule 12.09.2019