Преобразование короткого замыкания в краткое без знака и сохранение путаницы с битовой комбинацией - PullRequest
2 голосов
/ 05 мая 2020

Я работаю над проектом, в котором мне нужно получить ряд подписанных 16-битных целых чисел, отрицательных и положительных значений и отправить их в функцию для анализа во время модульных тестов.

По разным причинам функция принимает только массив беззнаковых 16-битных целых чисел, поэтому мне нужно сохранить подписанные целые числа в беззнаковом 16-битном целочисленном массиве и полностью сохранить тот же битовый шаблон. Я использую g cc (Debian 8.3.0-6) 8.3.0.

unsigned short arr[450];
unsigned short arrIndex = 0;

for (short i = -32768; i < (32767 - 100) ; i = i + 100 )
{
    arr[arrIndex] = i; 

    printf("short value is          : %d\n", i);
    printf("unsigned short value is : %d\n", arr[arrIndex]);
    arrIndex++;
}

Даже несмотря на то, что я говорю printf печатать значения со знаком, я удивлен, увидев, что битовые шаблоны на самом деле отличаются для тех значений, которые меньше нуля. Ниже приведены несколько первых значений:

short value is           : -32768
unsigned short value is  : 32768

short value is           : -32668
unsigned short value is  : 32868

short value is           : -32568
unsigned short value is  : 32968

Что здесь происходит, и как мне сохранить битовый шаблон для значений i ниже нуля?

Ответы [ 5 ]

3 голосов
/ 05 мая 2020

как мне сохранить битовый шаблон для значений i ниже нуля?

При очень распространенном кодировке с дополнением до 2 достаточно следующего.

unsigned short us = (unsigned short) some_signed_short;

BITD день с дополнением до единиц и величиной знака, этого было недостаточно, и код использовал бы union из short и unsigned short.

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


битовые комбинации фактически отличаются для тех значений, которые меньше нуля.

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


При печати short, unsigned short лучше всего использовать модификатор ah printf.

//printf("short value is          : %d\n", i);
//printf("unsigned short value is : %d\n", arr[arrIndex]);
printf("short value is          : %hd\n", i);
printf("unsigned short value is : %hu\n", arr[arrIndex]);
2 голосов
/ 05 мая 2020

Значения копируются правильно. Давайте посмотрим на следующий код:

#include <stdio.h>

void printit(char *name, short int val)
  {
  printf("%s  %hd  %hu  0x%hX\n", name, val, val, val);
  }

int main()
  {
  short int v1 = 0x8000;
  short int v2 = 0x8064;
  short int v3 = 0x80C8;

  printit("v1", v1);
  printit("v2", v2);
  printit("v3", v3);
  }

Здесь я создал четыре коротких подписанных переменных и установил для них битовые шаблоны. Забудьте на мгновение о «положительном» и «отрицательном» - я просто добавляю небольшой шаблон в эти переменные. В подпрограмме printit эти значения печатаются как десятичное со знаком, десятичное без знака и шестнадцатеричное (чтобы убедиться, что это один и тот же битовый шаблон). Теперь посмотрите на результаты:

v1  -32768  32768  0x8000
v2  -32668  32868  0x8064
v3  -32568  32968  0x80C8

Теперь вы можете видеть, что я просто скопировал использованные вами значения (-32768, -32668 и -32568) и присвоил их переменным. Единственная разница в том, что я сначала преобразовал их в шестнадцатеричный. Тот же битовый шаблон. Те же результаты. Но, за исключением нескольких редких случаев, интерпретация знакового десятичного значения битового шаблона, где десятичное значение является отрицательным, НЕ совпадает с беззнаковой десятичной интерпретацией битового шаблона. Я предлагаю прочитать Дополнение до одного для двоичных чисел и Дополнение до двух представление отрицательных двоичных чисел.

2 голосов
/ 05 мая 2020

В C, если вы вызываете вариационную функцию c и передаете целочисленный тип любого вида, язык автоматически продвигает его до знакового или беззнакового int того же типа. Когда вы затем распечатываете данные с помощью модификатора %d, в результате вы видите повышенное значение int.

Например, когда вы вызываете

printf("short value is          : %d\n", i);

(отрицательное) значение из i повышается до signed int с тем же значением, поэтому он распечатывается как отрицательный. Когда вы затем вызываете

printf("unsigned short value is : %d\n", arr[arrIndex]);

(беззнаковое) значение arr[arrIndex] повышается до unsigned int, поэтому отображается положительное значение.

Чтобы исправить это, измените свой printf, чтобы вы указали компилятору отображать результаты конкретно как short переменные:

printf("short value is          : %hd\n", i);
printf("unsigned short value is : %hd\n", arr[arrIndex]);

Теперь вы увидите, что значения совпадают.

1 голос
/ 05 мая 2020

Данные копируются правильно, побитно, как вы хотели. Это просто печать, которая отображает его как значение со знаком, потому что arr объявлен как массив значений без знака.

%d печатает данные, переданные как int s (по стандартному определению? Не уверен ), который на обычных платформах составляет 4 байта. Аргумент, переданный в printf, перед печатью обновляется до int, что, в зависимости от того, подписан ли рассматриваемый аргумент или нет, потребует расширения знака или нет.

При печати i, который является значением со знаком, перед печатью значение будет расширено со знаком. Например, если i равно -1 (что представлено как 0xFFFF в 2-байтовом значении со знаком с использованием дополнения до двух), то i будет обновлено до int значение 0xFFFFFFFF (которое также -1, но представлено четырьмя байтами).

Однако, если i равно -1, то при выполнении arr[arrIndex] = i arr[arrIndex] действительно будет установлено в 0xFFFF, копируется по крупицам, как вы хотели. Однако, поскольку arr[arrIndex] беззнаковый, в мире беззнакового 0xFFFF представляет 65535. Затем, когда придет время печатать arr[arrIndex], поскольку arr[arrIndex] беззнаковое, значение будет не будет расширено по знаку, так как это беззнаковое значение. Поэтому 0xFFFF будет обновлено до 0x0000FFFF, что равно 65535, и будет напечатано как таковое.

Мы можем проверить это, заставив arr считаться подписанным перед печатью. Таким образом, arr будет обрабатываться так же, как i.

#include <stdio.h>
int main() {
    unsigned short arr[450];
    unsigned short arrIndex = 0;

    for (signed short i = -32768; i < (32767 - 100) ; i = i + 100 )
    {
        arr[arrIndex] = i;
        printf("short value is          : %d\n", i);
        printf("unsigned short value is : %d\n", ((signed short*)arr)[arrIndex]);
        arrIndex++;
    }
}

Вывод:

short value is          : -32768
unsigned short value is : -32768
short value is          : -32668
unsigned short value is : -32668
short value is          : -32568
unsigned short value is : -32568
short value is          : -32468
unsigned short value is : -32468
short value is          : -32368
unsigned short value is : -32368
short value is          : -32268
unsigned short value is : -32268
short value is          : -32168
unsigned short value is : -32168

Или мы могли бы напрямую объявить arr как массив значений со знаком для достижения того же результата:

#include <stdio.h>
int main() {
    signed short arr[450];
    unsigned short arrIndex = 0;

    for (signed short i = -32768; i < (32767 - 100) ; i = i + 100 )
    {
        arr[arrIndex] = i;
        printf("short value is          : %d\n", i);
        printf("unsigned short value is : %d\n", arr[arrIndex]);
        arrIndex++;
    }
}
0 голосов
/ 06 мая 2020

Пожалуйста, проверьте пределы for l oop, как если бы вы go от -32768 до <(32767-100) скачкообразно 100 значений, вы заполняете 655 элементы массива, и вы только объявили 450 .

Кроме того, чтобы напечатать значение unsigned short, вам нужно использовать %u (или эквивалент %hu, как short s преобразуются в int для printf() использования) спецификатор формата.

Используйте этот пример:

#include <stdio.h>

int main()
{
        short i;
        for (i = -32768; i < (32767 - 100); i += 100) {
                unsigned short j = i;
                printf("Signed  : %d\n", i);
                printf("Unsigned: %u\n", j);
        }

        return 0;
}

Это даст:

$ a.out
Signed  : -32768
Unsigned: 32768
Signed  : -32668
Unsigned: 32868
Signed  : -32568
Unsigned: 32968
Signed  : -32468
...
Signed  : -268
Unsigned: 65268
Signed  : -168
Unsigned: 65368
Signed  : -68
Unsigned: 65468
Signed  : 32
Unsigned: 32
Signed  : 132
Unsigned: 132
...
Signed  : 32432
Unsigned: 32432
Signed  : 32532
Unsigned: 32532
Signed  : 32632
Unsigned: 32632
$ _
...