Reputation: 283013
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
?
Upvotes: 0
Views: 95
Reputation: 283013
A full solution for anyone that needs to pull out random bits from a 32-bit int:
function decrep($bin) {
return hexdec(bin2hex($bin));
}
function binrep($bin,$len=32) {
return implode(' ',str_split(str_pad(decbin(hexdec(bin2hex($bin))),$len,'0',STR_PAD_LEFT),8));
}
function extractBits($data,$pos,$len=1,$size=32) {
$bits = (1<<$len)-1;
$shift = $size - $pos - $len;
$mask = pack('N',$bits << $shift);
return (decrep($data) & decrep($mask)) >> $shift;
}
Usage:
$result = extractBits($data,1,2); // pulls out the 2nd and 3rd to left bit, returns number in range 0-3
Upvotes: 0
Reputation: 3044
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:
function decrep($bin)
{
return hexdec(bin2hex($bin));
}
then did the shift to the right using this function binrep(pack('N',((decrep($data) & decrep($mask)) >> $shift)))
and this gives the correct result.
Upvotes: 1