Преобразовать 8-разрядное целое число со знаком в беззнаковое, а затем преобразовать в int32

#c #integer

Вопрос:

У меня есть 8-разрядное целое число со знаком ( int8_t ), которое может быть любым значением от -5 до 5 , и его нужно преобразовать в 8-разрядное целое число без знака ( uint8_t ).

uint8_t Затем это значение передается другому аппаратному обеспечению (которое может обрабатывать только 32-разрядные типы) и должно быть преобразовано в a int32_t .

Как я могу это сделать?

Пример кода:

 #include <stdio.h>
#include <stdint.h>

void main() {

    int8_t input;
    uint8_t package;
    int32_t output;

    input = -5;
    package = (uint8_t)input;
    output = (int32_t)package;

    printf("output = %d",output);
}
 

В этом примере я начинаю с -5 . Он временно преобразуется в 251 , чтобы его можно было упаковать как uint8_t . Затем эти данные отправляются на другое оборудование, где я не могу использовать (int8_t) для преобразования 8-разрядного целого числа без знака обратно в signed перед приведением к int32_t . В конечном счете, я хочу иметь возможность получить исходное -5 значение.

Для получения дополнительной информации принимающее оборудование представляет собой процессор SHARC, который не позволяет int8_t — см. https://ez.analog.com/dsp/sharc-processors/f/q-a/118470/error-using-stdint-h-types

Наименьший адресуемый блок памяти в процессоре SHARC равен 32 битам, что означает, что минимальный размер любого типа данных равен 32 битам. Это относится к собственным типам C, таким как char и short . Поскольку типы «int8_t», «uint16_t» указывают, что размер типа должен составлять 8 бит и 16 бит соответственно, они не могут поддерживаться для SHARC.

Комментарии:

1. Это действительно зависит от того, что вы подразумеваете под «конвертировать». Что вы ожидаете -5 получить, когда преобразуете его из int8_t в uint8_t ? В вашем текущем коде это становится 251 .

2. Реальный вопрос здесь в том, почему вам нужно сначала пройти uint8_t ? Потому что вы хотите сохранить 8-разрядное значение без знака, а затем расширить его до 32 бит?

3. Спасибо за ваш комментарий — это связано с аппаратными ограничениями. Я отправляю данные с одного устройства на другое. Все данные должны быть отправлены в 8-битных целочисленных пакетах без знака. Но аппаратное обеспечение, которое я получаю, не позволяет мне выполнять преобразование в (int8_t) перед приведением к int32_t

4. Вам нужно будет уточнить, каким вы хотите, чтобы ваш конечный результат был на нескольких примерах, мы не можем просто догадаться, что вы хотите сделать. Вы хотите -5 , чтобы значение оставалось -5 таким, когда оно будет окончательно преобразовано в int32_t ?

5. Кажется, что ваши требования мутные. Аппаратному обеспечению обычно не нужны числа со знаком. Какую реальную проблему вы пытаетесь решить? Вы пытаетесь изобрести протокол передачи данных? Затем для этого протокола необходимо указать подписанность, конечность и т.д., и каждый процессор, использующий его, должен конвертировать в / из этого протокола.

Ответ №1:

Вот одно из возможных преобразований без ветвей:

 output = package; // range 0 to 255
output -= (output amp; 0x80) << 1;
 

Во второй строке будет вычтено 256, если установлен бит 7, например:

  • 251 имеет установленный бит 7, 251 — 256 = -5
  • у 5 бит 7 очищен, 5 — 0 = 5

Комментарии:

1. Я бы предпочел проверить инструкцию расширения знака и использовать ее как встроенную. Эти процессоры запрограммированы наиболее эффективным способом, игнорируя переносимость.

Ответ №2:

Если вы хотите вернуть отрицательный знак, используя 32-разрядные операции, вы могли бы сделать что-то вроде этого:

    output = (int32_t)package;
   if (output amp; 0x80) { /* char sign bit set */
        output |= 0xffffff00;
   }

   printf("output = %d",output);
 

Ответ №3:

Поскольку ваша платформа получателя не имеет типов шириной менее 32 бит, ваш самый простой вариант — решить эту проблему на отправителе:

 int8_t input = -5;
int32_t input_extended = input;
uint8_t buffer[4];

memcpy(buffer, amp;input_extended, 4);

send_data(buffer, 4);
 

Затем на принимающей стороне вы можете просто обрабатывать данные как единый int32_t :

 int32_t received_data;

receive_data(amp;received_data, 4);
 

Все это предполагает, что ваш отправитель и получатель имеют одинаковый порядковый номер. Если нет, вам придется перевернуть порядковый номер отправителя перед отправкой:

 int8_t input = -5;
int32_t input_extended = input;
uint32_t tmp = (uint32_t)input_extended;

tmp = ((tmp >> 24) amp; 0x000000ff)
    | ((tmp >>  8) amp; 0x0000ff00)
    | ((tmp <<  8) amp; 0x00ff0000)
    | ((tmp << 24) amp; 0xff000000);

uint8_t buffer[4];

memcpy(buffer, amp;tmp, 4);

send_data(buffer, 4);
 

Ответ №4:

Просто вычтите 256 из значения, потому что в дополнении 2 n-битное отрицательное значение v сохраняется как 2 n — v

 input = -5;
package = (uint8_t)input;
output = package > 127 ? (int32_t)package - 256 : package;
 

Ответ №5:

Редактировать:

Если проблема в том, что в вашем коде есть if операторы для значений -5 to 5 , то самым простым решением может быть проверка result 5 и изменение if операторов на значения между 0 и 10 .

Вероятно, это то, что компилятор будет делать при оптимизации (поскольку значения 0-10 могут быть преобразованы в map, избегая if операторов и минимизируя прогностическую очистку процессора).


Оригинал:

Приведение типов будет работать, если сначала приведено к uint8_t , а затем uint32_t

 output = (int32_t)(uint32_t)(uint8_t)input;
 

Конечно, если установлен 8-й бит, он останется установленным, но знак не будет расширен, поскольку операция приведения типов сообщает компилятору обрабатывать 8-й бит как обычный бит (он без знака).

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

Кодекс:

 #include <stdint.h>
#include <stdio.h>

void main() {

  int8_t input;
  int32_t output;

  input = -5;
  output = (int32_t)(uint32_t)(uint8_t)input;

  printf("output = %dn", output);
}
 

Приводит к « output = 251 «.