【问题标题】:Pack / unpack a 64-bit int on 64-bit architecture in PHP在 PHP 中的 64 位架构上打包/解包 64 位 int
【发布时间】:2011-03-16 23:16:01
【问题描述】:

为什么我会在 x64 架构上得到以下输出?

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

它似乎可以处理带符号的 64 位整数,但不能打包/解包它们。根据文档http://us3.php.net/pack,I 的大小应该取决于机器,在这种情况下是 64 位。

$ 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

【问题讨论】:

  • echo PHP_INT_MAX; 带给你什么?
  • 你运行的是什么版本的 PHP?
  • @Wrikken 和@R。希尔,请参阅上面的编辑。
  • 我也是64位的机器,bin2hex(pack("I",pow(2,33)))的输出确实是"00000000",所以就好像机器- 依赖整数是 32 位的,无论底层架构如何。我想“机器相关”意味着永远不要假设一个特定的大小,即使是关于一个正在运行的环境。一个想法:由于 pack() 没有为高于 32 位整数的任何内容提供显式格式,因此我们不能期望包含更多 32 位整数的整数可能被打包是有道理的。在这种情况下,“机器相关”实际上是指 16 位或 32 位。

标签: php binary 64-bit pack unpack


【解决方案1】:

这是一个将任意大小的整数值打包成 N 位的函数:

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;
}

这是一个解码打包整数的函数:

    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;
    }

【讨论】:

    【解决方案2】:

    pack("I") 请求一个整数,对于 x86_64 上的 I32LP64 模型,它通常仍然是 32 位宽 - 至少在 C 中是这样。解释器通常在顶部添加自己的定义。

    【讨论】:

      【解决方案3】:

      没有 64 位版本的 PHP 5.2。第一个 64 位版本是 Windows 端 5.3.0 的实验版本。因此,如果您在 Windows 上使用 5.2.9,则必须至少升级到 5.3.0 才能获得 64 位版本。

      如果我的前提是正确的,并且您在 Windows 上使用 PHP,那么这就是它不起作用的方式......

      为了让您能够访问 CPU 的 64 位组件,您的整个堆栈必须是 64 位。这意味着 CPU 必须支持 64 位,操作系统必须支持 64 位,应用程序必须支持 64 位。如果其中任何一个使用 32 位,则从那时起整个堆栈将是 32 位。它遵循最小的公分母。

      【讨论】:

        【解决方案4】:

        因为 pack 将第二个参数作为字符串并将其转换为 32 位 int。就位大小限制而言,唯一的救济是无符号的。查看源代码,我看到 Perl 即将推出一个 64 位版本,它使用“Q”来强制 64 位机器字节序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-11-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-27
          • 1970-01-01
          • 2014-01-10
          相关资源
          最近更新 更多