Anding um inteiro com 0xFF
deixa apenas o byte menos significativo. Por exemplo, para obter o primeiro byte em um short s
, você pode escrever s & 0xFF
. Isso é normalmente referido como”mascaramento”. Se byte1
for um único tipo de byte (como uint8_t
) ou já tiver menos de 256 (e, como resultado, todos os zeros, exceto o byte menos significativo), não há necessidade de mascarar os bits mais altos, pois eles já são zero.
veja a resposta de tristopiaPatrick Schlüter abaixo quando você pode estar trabalhando com tipos assinados. Ao fazer operações bit a bit, recomendo trabalhar apenas com tipos não assinados.
se byte1
é um número inteiro de 8 bits tipo, então é inútil – se é mais do que 8 bits que será, essencialmente, dar-lhe os últimos 8 bits do valor:
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
O perigo da segunda expressão vem se o tipo de byte1
é char
. Nesse caso, algumas implementações podem tê-lo signed char
, o que resultará em extensão de sinal ao avaliar.
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);
irá imprimir
value1=4224 1080 rightvalue2=65408 ff80 wrong!!
eu tentei no gcc v3.4.6 no Solaris SPARC 64 bit e o resultado é o mesmo com byte1
e byte2
declarados como char
.
TL;DR
o mascaramento é evitar a extensão implícita do sinal.
editar: verifiquei, é o mesmo comportamento em C++.
EDIT2: conforme solicitado explicação da extensão do sinal.A extensão de sinal é uma consequência da maneira como C avalia expressões. Existe uma regra em C chamada regra de promoção. C lançará implicitamente todos os tipos pequenos para int
antes de fazer a avaliação. Vamos ver o que acontece com a nossa expressão:
unsigned short value2 = ((byte2 << 8) | byte1);
byte1
é uma variável contendo padrão de bits 0xFF. Se char
for unsigned
esse valor é interpretado como 255, se for signed
é -128. Ao fazer o cálculo, C estenderá o valor para um tamanho int
(16 ou 32 bits geralmente). Isso significa que se a variável for unsigned
e mantermos o valor 255, o padrão de bits desse valor como int
será 0x000000FF. Se for signed
queremos o valor -128 Qual padrão de bits é 0xFFFFFFFF. O sinal foi estendido para o tamanho da tempory usada para fazer o cálculo.E assim oring o temporário produzirá o resultado errado.
na montagem x86 é feito com a instrução movsx
(movzx
para a extensão zero). Outras CPUs tinham outras instruções para isso (6809 tinha SEX
).