Побитовая распаковка с использованием подписанных данных - PullRequest
1 голос
/ 13 октября 2011

Я некоторое время пытался упаковать и распаковать несколько символов в целое число. Хотя есть некоторые темы, связанные с этим вопросом, моя проблема связана с подписанной сменой. Я не понимаю, как распаковать подписанное значение, т.е.

char c1 = -119;
char c2 = 26;

// pack
int packed = (unsigned char)c1 | (c2 << 8);
// unpack
c1 = packed >> 0;
c2 = packed >> 8;

// printf(c1, c2) -> Unpacked data: -119 | 26

Это работает, как и ожидалось, но когда я пытаюсь упаковать больше данных, т.е.:

char c0 = -42;
char c1 = -119;
char c2 = 26;

// pack
int packed = (unsigned char)c0 | (unsigned char)(c1 << 8) | (c2 << 16);
// unpack
c0 = packed >> 0;
c1 = packed >> 8;
c2 = packed >> 16;

// printf -> Unpacked data: -42 | 0 | 26

c1 значение пропущено. Я предполагаю, что это связано с чем-то с бит знака смещен в старшую позицию .

Как я могу вернуть c1 значение?

Заранее спасибо.

Ответы [ 3 ]

4 голосов
/ 13 октября 2011

Вы применяете c1 к unsigned char после смещения его за пределы диапазона этого типа, поэтому результат применения равен нулю. Вы должны выполнить приведение перед сдвигом:

int packed = (unsigned char)c0 | ((unsigned char)c1 << 8) | (c2 << 16);
2 голосов
/ 13 октября 2011
(unsigned char)(c1 << 8)

Это будет

  • сдвинуть неправильное (расширенное знаком) значение
  • обрезать результат до 8 бит (получая 0)

Вам не нужно ничего из этого, поэтому вы должны использовать ((unsigned char)c1 << 8).

0 голосов
/ 13 октября 2011

Некоторые int с 16 бит. Для того, чтобы этот код был переносимым, используйте int32_t. Правильный способ сделать это (если немного параноидален):

int32_t packed = ((uint8_t)c0) | (((uint8_t)c1)<<8) | (((uint8_t)c2) << 16);

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

...