代码之家  ›  专栏  ›  技术社区  ›  Kris Erickson

强制PHP整数溢出

  •  7
  • Kris Erickson  · 技术社区  · 16 年前

    我们有一些整数算法,由于历史原因,它在PHP上的工作方式与在一些静态类型语言中的工作方式相同。自从我们上次升级PHP以来,溢出整数的行为已经改变。基本上,我们使用以下公式:

    function f($x1, $x2, $x3, $x4)
    {
       return (($x1 + $x2) ^ $x3) + $x4;
    }
    

    但是,即使进行了转换:

    function f($x1, $x2, $x3, $x4)
    {
       return intval(intval(intval($x1 + $x2) ^ $x3) + $x4);
    }
    

    例如,对于$x1=-1580033017、$x2=-2072974554、$x3=-1170476976)和$x4=-1007518822,我在PHP中得到了-30512150,在C#中得到了1617621783。

    在C#中,我得到

    (-1580033017 + -2072974554) = 641959725
    

    在PHP中:

    intval(intval(-1580033017) + intval(-2072974554)) = -2147483648
    

    intval(-1580033017 + -2072974554) = -2147483648
    

    我不介意写一个“IntegerOverflowAdd”函数之类的东西,但我不太明白(-1580033017+-2072974554)如何等于641959725。(我确实知道它是-2147483648+(2*2^31),但是-2147483648+2^31是-1505523923,它大于Int.Min,那么为什么要加2*2^31而不是2^31呢?)

    6 回复  |  直到 16 年前
        1
  •  14
  •   Leopoldo Sanczyk    5 年前

    所以我解决了这个问题,发现了很多关于PHP的东西(至少在它处理整数溢出的方式上)。

    1) 这完全取决于机器运行在哪个平台上,哪个版本的PHP,是否运行了Suhosin加固的PHP,以及编译了多少位(32位或64位)。6台机器的行为符合我的预期(这实际上是错误的,至少根据他们的文档是错误的),3台机器的行为符合我仍然无法解释的方式,3台机器的行为符合intval命令在文档中的说明。

    2) 当INT>时,Intval应该返回PHP_INT_MAX;PHP_INT_MAX(不是INT&0xffffffff),但这只发生在某些版本的PHP4和PHP5上。int>时,不同版本的PHP返回不同的值;PHP_INT_MAX。

    3) 以下代码可以返回3个不同的结果(请参见1):

    <?php
    echo "Php max int: ".PHP_INT_MAX."\n";
    echo "The Val: ".(-1580033017 + -2072974554)."\n";
    echo "Intval of the val: ".intval(-3653007571)."\n";
    echo "And 0xffffffff of the val: ".(-3653007571 & 0xffffffff)."\n";
    ?>
    

    它可以返回(对于Intval来说似乎是正确的,但是对于&0xffffff来说是错误的)

    Php max int: 2147483647
    The Val: -3653007571
    Intval of the val: -2147483648
    And of the val: -2147483648
    

    Php max int: 2147483647
    The Val: -3653007571
    Intval of the val: -641959725
    And of the val: -641959725
    

    在64位机器上,它返回(这是正确的):

    Php max int: 2147483647
    The Val: -3653007571
    Intval of the val: -3653007571
    And of the val: -641959725
    

    无论如何,我需要一个能够在所有这些平台上工作的解决方案,并且不依赖于使用特定Max int编译的特定版本的PHP的怪癖。因此,我可以使用以下跨PHP thirtyTwoBitIntval函数:

    function thirtyTwoBitIntval($value)
    {
        if ($value < -2147483648)
        {
            return -(-($value) & 0xffffffff);
        }
        elseif ($value > 2147483647)
        {
            return ($value & 0xffffffff);
        }
        return $value;
    }
    

        2
  •  11
  •   user257425 user257425    15 年前

    如果您希望在32位和64位平台上都有32位intval的100%工作解决方案,那么我建议您使用以下解决方案:

    function intval32bits($value)
    {
        $value = ($value & 0xFFFFFFFF);
    
        if ($value & 0x80000000)
            $value = -((~$value & 0xFFFFFFFF) + 1);
    
        return $value;
    }
    
        3
  •  3
  •   kylex    16 年前

    在内部,PHP对大多数数字使用“整数”类型。然而,这些只是到此为止:如果您将一个大整数添加到一个大整数中,PHP将看到结果太大,无法放入一个普通整数中,并将其分配给一个浮点数。然而,浮点数(float)本身的值只有这么高,在16位数字附近有一个点,PHP将完全失去绘图功能。

    有一个选项可以使用任意精度的数学 支持任何大小和精度的数字,以字符串表示 . 请参阅此处的更多信息: http://us2.php.net/bc

        5
  •  2
  •   C. K. Young    16 年前

    echo (-1580033017 + -2072974554) & 0xffffffff
    

    概括而言,您可以这样做(请原谅任何语法错误,我很久没有接触过PHP):

    function s32add($a, $b) {
        return ($a + $b) & 0xffffffff;
    }
    
        6
  •  1
  •   JasonMichael    16 年前

    检查您的PHP版本号-我相信,不同版本的PHP对长整数的支持可能不同,您可能会得到不同的结果。我相信在最后一个PHP5版本中有一个带有长整数的bug。

    在PHP5.2.0版本中,答案与在C中得到的答案完全相同#

    1617621783,

    利用上面的确切功能。

    phpinfo() 命令以轻松查找您的版本号。

    $x1 = -1580033017; 
    $x2 = -2072974554; 
    $x3 = -1170476976 ; 
    $x4 = -1007518822;
    echo f($x1, $x2, $x3, $x4);
    
    function f($x1, $x2, $x3, $x4)
    {
       return intval(intval(intval($x1 + $x2) ^ $x3) + $x4);
    }