#c #c #bit-manipulation #bitwise-operators
#c #c #манипулирование битами #побитовые операторы
Вопрос:
Я некоторое время пытался упаковать и распаковать некоторые символы в целое число. Хотя есть некоторые темы, связанные с этим вопросом, моя проблема связана с подписанным сдвигом. Я не понимаю «трюк» для распаковки подписанного значения, т.е.:
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?
Заранее спасибо.
Ответ №1:
Вы выполняете приведение c1
к unsigned char
после смещения его из диапазона этого типа, поэтому результат приведения равен нулю. Вы должны выполнить приведение перед переносом:
int packed = (unsigned char)c0 | ((unsigned char)c1 << 8) | (c2 << 16);
Комментарии:
1. Хорошее объяснение 🙂 Сомнениям нет места. Спасибо вам!
Ответ №2:
(unsigned char)(c1 << 8)
Это приведет
- смещение неправильного (расширенного по знаку) значения
- обрезать результат до 8 бит (получая 0)
Вам ничего этого не нужно, поэтому вы должны использовать ((unsigned char)c1 << 8)
.
Комментарии:
1. Неверно. Приведение signed к unsigned никогда не является неопределенным поведением, независимо от того, насколько широки или узки типы. (В отличие от преобразования unsigned в signed .). Код по-прежнему неправильный, но это не UB.
Ответ №3:
Некоторые int
s составляют 16 бит. Чтобы этот код был переносимым, используйте int32_t
. Правильный способ добиться этого (если немного параноидальный):
int32_t packed = ((uint8_t)c0) | (((uint8_t)c1)<<8) | (((uint8_t)c2) << 16);
Я также склонен перечислять их в обратном порядке, поэтому более естественно, какие символы становятся наиболее и наименее значимыми байтами.