В следующем коде:
short = ((byte2 << 8) | (byte1 & 0xFF))
Какова цель &0xFF
?
Потому что в других случаях я вижу это как:
short = ((byte2 << 8) | byte1)
И это тоже хорошо работает?
В следующем коде:
short = ((byte2 << 8) | (byte1 & 0xFF))
Какова цель &0xFF
?
Потому что в других случаях я вижу это как:
short = ((byte2 << 8) | byte1)
И это тоже хорошо работает?
Анинг целое с 0xFF
оставляет только младший значащий байт. Например, чтобы получить первый байт в short s
, вы можете написать s & 0xFF
. Обычно это называется "маскировка". Если byte1
является либо одиночным байтовым типом (например, uint8_t
), либо уже менее 256 (и, как результат, все нули, за исключением младшего значащего байта), нет необходимости маскировать более высокие биты, поскольку они уже равны нулю.
См. tristopia Патрик Шлютер ниже, когда вы можете работать со подписанными типами. При выполнении побитовых операций я рекомендую работать только с неподписанными типами.
если byte1
- это 8-разрядный целочисленный тип, то он бессмыслен - если он больше 8 бит, он по существу даст вам последние 8 бит значения:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
& 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
-------------------------------
0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1
Опасность второго выражения возникает, если тип byte1
равен char
. В этом случае некоторые реализации могут иметь его signed char
, что приведет к расширению знака при оценке.
signed char byte1 = 0x80;
signed char byte2 = 0x10;
unsigned short value1 = ((byte2 << 8) | (byte1 & 0xFF));
unsigned short value2 = ((byte2 << 8) | byte1);
printf("value1=%hu %hx\n", value1, value1);
printf("value2=%hu %hx\n", value2, value2);
напечатает
value1=4224 1080 right
value2=65408 ff80 wrong!!
Я попробовал это на gcc v3.4.6 на Solaris SPARC 64 бит, и результат совпадает с byte1
и byte2
, объявленным как char
.
TL; DR
Маскировка заключается в том, чтобы избежать неявного расширения знака.
EDIT: Я проверил, это то же поведение в С++.
Предполагая, что ваш byte1
является байтом (8 бит), Когда вы выполняете побитовое И байта с 0xFF, вы получаете один и тот же байт.
Итак, byte1
совпадает с byte1 & 0xFF
Скажите byte1
01001101
, затем byte1 & 0xFF = 01001101 & 11111111 = 01001101 = byte1
Если byte1 имеет какой-то другой тип, скажите целое число из 4 байтов, побитовое И с 0xFF оставляет вам младший байт (8 бит) байта1.
byte1 & 0xff
гарантирует, что только 8 младших значащих бит byte1
могут быть отличными от нуля.
если byte1
уже является неподписанным типом, который имеет только 8 бит (например, char
в некоторых случаях или unsigned char
в большинстве), он не будет иметь никакого значения/совершенно ненужным.
Если byte1
- это тип, который подписан или имеет более 8 бит (например, short
, int
, long
), и любой из битов, кроме 8 наименее значимых, устанавливается (т.е. он будет обнулять эти верхние биты до or
с другой переменной, поэтому этот операнд or
влияет только на 8 наименее значимых бит результата).
он очищает все биты, которые не находятся в первом байте
& 0xFF
сам по себе гарантирует, что если байты длиннее 8 бит (допускается стандартом языка), остальные игнорируются.
И это тоже хорошо работает?
Если результат заканчивается больше SHRT_MAX
, вы получаете поведение undefined. В этом отношении обе будут работать одинаково плохо.