Force PHP整数溢出

问题描述 投票:8回答:6

[我们有一些整数算法,由于历史原因,它必须在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。

仅将$ x1和$ x2加在一起,我不能得到正确的答案:

在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?]

任何帮助将不胜感激...

c# php integer-overflow
6个回答
14
投票

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

1]完全取决于机器在哪个平台上运行,哪个版本的PHP,是否运行Suhosin Hardened PHP以及它针对多少位(32或64)进行编译之间的交叉。 6台计算机的行为符合我的预期(实际上是错误的,至少根据他们的文档是错误的)和3台计算机的行为依旧无法解释,而3台计算机的行为则是根据intval命令说的来完成的。文档。

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

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

它可以返回(与intval的PHP文档相矛盾:]

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的threenTwoBitIntval函数:

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

评论

我确实认为PHP的设计师应该说一个Int是32位Int,无论它是在32位,64位还是128位机器上运行(例如DotNet CLR),并且没有随机地对其进行升频转换。浮点数,具体取决于PHP编译器所依据的位数。


11
投票

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


3
投票

[内部,PHP对大多数数字使用“整数”类型。但是,它们仅适用于此:如果将一个大整数添加到一个大整数中,PHP将看到结果太大而无法容纳普通整数并将其分配给浮点数。但是,浮点数(floats)本身仅是如此之高,而在十六位标记附近存在一点,PHP将完全失去该图。


2
投票

我认为这可能与PHP中的整数是无符号的32位有关,因为在C#中,它们默认情况下是有符号的32位。


2
投票

这项工作会吗?


1
投票

检查您的PHP版本号-我相信使用不同版本的PHP(可能对长整数的支持不同)可能会得到不同的结果。我相信在PHP 5的最后一个版本中存在一个长整数错误。

© www.soinside.com 2019 - 2024. All rights reserved.