php - Right shift not working as expected

319

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

?

874

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:

function decrep($bin)
{
return hexdec(bin2hex($bin));
}

then did the shift to the right using this functionbinrep(pack('N',((decrep($data) & decrep($mask)) >> $shift))) and this gives the correct result.

160

Answer

Solution:

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

People are also looking for solutions to the problem: php - what does ($variable) return?

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.