php - Right shift not working as expected
I need to do some bit twiddling to pull out some data I'm getting from another source.
The data I've got looks like this in binary:
01100011 00000000 00000000 00000000
Which is the little-endian encoding of the decimal number 99.
I want to mask (bitwise-and) it with this value:
01000000 00000000 00000000 00000000
And then shift all the way to the right (30 places).
When I try right-shifting it, however, I get:
00000000 00000000 00000000 00110000
And I can't figure out why.
Here's the code:
function binrep($bin,$len=32) {
return implode(' ',str_split(str_pad(decbin(hexdec(bin2hex($bin))),$len,'0',STR_PAD_LEFT),8));
}
function mask($data,$pos,$len=1,$size=32) {
$bits = (1<<$len)-1;
$shift = $size - $pos - $len;
$mask = pack('N',$bits << $shift);
echo binrep($data)."\n".binrep($mask)."\n".binrep(($data&$mask)>>$shift);
return ($data & $mask) >> $shift;
}
mask(pack('V',99),1);
Where is that value coming from? Why isn't the result
00000000 00000000 00000000 00000001
?
Answer
Solution:
This is a type mismatch. Since
($data & $mask)
evaluates to a string, php is implicitly changing the type of$shift
to a string to do the operation. And as per the php documentation, this means the>>
operator is using ascii values to do the calculation. I added this function to your code:then did the shift to the right using this function
binrep(pack('N',((decrep($data) & decrep($mask)) >> $shift)))
and this gives the correct result.Answer
Solution:
A full solution for anyone that needs to pull out random bits from a 32-bit int:
Usage: