4

Why do I get the following output on an x64 architecture?

$ php -r 'echo pow(2, 33) . "\n";print_r(unpack("Ivalue", pack("I", pow(2, 33))));'
8589934592
Array
(
    [value] => 0
)

It seems as though it can handle signed 64-bit ints, but it can't pack / unpack them. According to the documentation, http://us3.php.net/pack, the size of I should be machine-dependent, which in this case is 64 bit.

$ php -r 'echo PHP_INT_MAX;'
9223372036854775807

$ php -v
PHP 5.2.9 (cli) (built: Apr 17 2009 03:29:14)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sberry
  • 128,281
  • 18
  • 138
  • 165
  • What does `echo PHP_INT_MAX;` give you? – Wrikken Jul 16 '10 at 13:33
  • What version of PHP are you running? – R. Hill Jul 16 '10 at 13:37
  • @Wrikken and @R. Hill, see the edits above. – sberry Jul 16 '10 at 13:41
  • I also am on a 64-bit machine, and the output of bin2hex(pack("I",pow(2,33))) is indeed "00000000", so it's as if the machine-dependent integer is 32-bit regardless of underlying architecture. I suppose "machine-dependent" means never assume a particular size, even with regard to which environment one is running. A thought: Since pack() doesn't provide explicit format for anything above 32-bit integer, maybe it makes sense that we can't expect integers with more 32-bit to be packed. in this case, "machine-dependent" really means 16- or 32-bit. – R. Hill Jul 16 '10 at 14:41

4 Answers4

2

Here is a function to pack an integer value of any size into N bits:

function encode_int($in, $pad_to_bits=64, $little_endian=true) {
    $in = decbin($in);
    $in = str_pad($in, $pad_to_bits, '0', STR_PAD_LEFT);
    $out = '';
    for ($i = 0, $len = strlen($in); $i < $len; $i += 8) {
        $out .= chr(bindec(substr($in,$i,8)));
    }
    if($little_endian) $out = strrev($out);
    return $out;
}

Here is a function to decode the packed integers:

    function decode_int(&$data, $bits=false) {
            if ($bits === false) $bits = strlen($data) * 8;
            if($bits <= 0 ) return false;
            switch($bits) {
                    case 8:
                            $return = unpack('C',$data);
                            $return = $return[1];
                    break;

                    case 16:
                            $return = unpack('v',$data);
                            $return = $return[1];
                    break;

                    case 24:
                            $return = unpack('ca/ab/cc', $data);
                            $return = $return['a'] + ($return['b'] << 8) + ($return['c'] << 16);
                    break;

                    case 32:
                            $return = unpack('V', $data);
                            $return = $return[1];
                    break;

                    case 48:
                            $return = unpack('va/vb/vc', $data);
                            $return = $return['a'] + ($return['b'] << 16) + ($return['c'] << 32);
                    break;

                    case 64:
                            $return = unpack('Va/Vb', $data);
                            $return = $return['a'] + ($return['b'] << 32);
                    break;

            }
            return $return;
    }
Justin Swanhart
  • 1,826
  • 13
  • 15
0

Because pack takes the second parameter as a string and converts it to a 32-bit int. The only relief is unsigned as far as bit-size limitations. Looking at the source code I see a 64-bit version coming soon from Perl that uses 'Q' to force 64-bit machine endian.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ppostma1
  • 3,616
  • 1
  • 27
  • 28
0

pack("I") requests an integer, which, for the I32LP64 model on x86_64 still is usually 32 bits wide - at least in C. Interpreters often add their own definition on top.

user502515
  • 4,346
  • 24
  • 20
0

There is no 64-bit version of PHP 5.2. The first 64-bit version was an experimental version of 5.3.0 on the Windows side. So if you're using 5.2.9 on Windows, you'll have to move up to 5.3.0 at least to be able to get a 64-bit build.

If my premise is correct, and you are using PHP on Windows, then this is way it's not working...

For you to have access to the 64-bit component of your CPU, your whole stack has to be 64 bits. That means that the CPU has to support 64 bit, the OS has to support 64 bit, and the application has to support 64 bit. If any of these use 32 bits, the the whole stack will be 32 bit from that point. It goes by the lowest common denominator.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark Tomlin
  • 8,593
  • 11
  • 57
  • 72