#c
#c
Вопрос:
Мне нужно объединить некоторые побитовые операции, но текущий вывод кажется неправильным. Разделенные операции аналогичны этому :
unsigned char a = 0x12
unsigned char x = 0x00;
x = a << 4;
x = x >> 4;
ожидаемый результат x = 0x02;
текущий результат x = 0x02;
Если я попытаюсь объединить операции, результат будет неверным:
unsigned char a = 0x12
unsigned char x = 0x00;
x = (a << 4) >> 4;
ожидаемый результат x = 0x02;
текущий результат x = 0x12;
Заранее спасибо за любые предложения.
Комментарии:
1. Что вы подразумеваете под «конкатенацией»? Чего вы ожидаете?
2. Результатом
a << 4
будет anint
, поэтому вы должны отбросить его назад раньше>> 4
, т. е.x = static_cast<unsigned char>(a << 4) >> 4;
.3. Это мое воображение, или вы выполнили операцию, отменили эту операцию, а затем ожидаете, что она выведет что-то отличное от оригинала. Здесь есть несколько хороших попыток найти ответы, так что я, вероятно, что-то упускаю. Можете ли вы (или кто-нибудь) объяснить, почему вы думаете, что это будет что-то другое, чем
0x12
?4. @Chipster
0x12 << 4
был0x120
бы, но он усекается0x20
при сохранении как anunsigned char
, поэтому его возврат только возвращает0x02
, а не0x12
. ответы объясняют, почему усечение происходит в случае 1, но не в случае 25. @kmdreko Ах, потому что теоретически это всего лишь символ. Понял тебя. Теперь это имеет смысл.
Ответ №1:
Проблема (a << 4)
заключается в приведении к int (через интегральное продвижение), поэтому (0x12 << 4) >> 4
по сути 0x12
Что вы хотите сделать, это преобразовать обратно (a << 4)
unsigned char
, используя static_cast
Окончательный код:
unsigned char a = 0x12;
unsigned char x = 0x00;
x = static_cast<unsigned char>(a << 4) >> 4;
Комментарии:
1. @Chipster суть в том, что он надеется, поскольку char равен 8 битам,
a << 4
дать 2, поскольку 1 превышает 8 битный размер. Жаль, что операция выполняется в int, и она никогда не стирается2. спасибо Мартину М. за ваше объяснение. я буду использовать ваше решение.
3. @Gardener если бы компилятор замаскировал здесь младшие 8 бит, даже на 8-разрядной машине, это было бы нарушением правил языка C , в частности [expr.shift]/1 , [conv.prom]/1 и [basic.fundamental]/4 …
Ответ №2:
Компилятор НЕ применяет интегральные поощрения для операций >> и <<
Вы можете подумать, что
x = (a << 4) >> 4;
Для операции использовался бы регистр шириной в байт, но компилятор преобразует char a в int перед выполнением сдвига, сохраняя биты, сдвинутые влево.
Вы можете решить эту проблему, выполнив это:
x = ((a << 4) amp; 0xff) >> 4;
Опять же, проблема в том, что интегральное продвижение сохраняет биты до окончательного приведения.
Комментарии:
1. Пожалуйста, обратите внимание, что проблема здесь не в том, что компилятор ничего не смог сделать. Проблема в том, что ожидания человека, написавшего этот код, не совпали с реальностью. По правилам языка C , операнды для встроенных
>>
<<
операторов и подлежат целому продвижению. Компилятор сделал именно то, что он всегда должен был делать, даже на 8-разрядном компьютере…2. спасибо за ваше объяснение, да, я не знал о продвижении integral.