Pack / unpack a 64-bit int on 64-bit architecture

2020-02-12 13:14发布

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

4条回答
萌系小妹纸
2楼-- · 2020-02-12 14:00

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.

查看更多
再贱就再见
3楼-- · 2020-02-12 14:03

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.

查看更多
Ridiculous、
4楼-- · 2020-02-12 14:05

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;
    }
查看更多
对你真心纯属浪费
5楼-- · 2020-02-12 14:06

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.

查看更多
登录 后发表回答