PHP 7中32位int整数下溢返回0的原因咨询
为什么PHP 7中32位整数相加会得到0,而PHP 5.5不会?
首先先看一下你提供的测试代码:
$z10 = (int)($z & 0xFFFFFFFF); $z11 = (int)($z5 & 0xFFFFFFFF); $z12 = (int)(((int)$z10 + (int)$z11) & 0xFFFFFFFF); $z10_type = gettype ( $z10); $z11_type = gettype ( $z11); $z12_type = gettype ( $z12); print "z10 " .dechex($z10) . " " . $z10_type . "\n"; print "z11 " .dechex($z11) . " " . $z11_type . "\n"; print "z12 " .dechex($z12) . " " . $z12_type . "\n"; $z = ((int)($z10 + $z11)) & 0xFFFFFFFF; print "z " .$z . "\n";
以及两个版本的输出:
PHP 7(32位硬件环境)运行结果:
z10 eb9c083c integer
z11 8d833a2f integer
z12 0 integer
z 0
PHP 5.5(32位硬件环境)运行结果:
z10 eb9c083c integer
z11 8d833a2f integer
z12 791f426b integer
z 2032091755
这个差异的根源是PHP 7彻底改变了32位环境下整数溢出后的类型转换规则,具体拆解如下:
1. PHP 5.5的处理逻辑
在32位环境中,PHP 5的int是32位有符号类型,范围是 -2147483648 到 2147483647。
- 你的
$z10(0xeb9c083c)和$z11(0x8d833a2f)作为32位有符号整数,实际是两个负数:-343928772和-1879644625。 - 两者相加的结果是
-2223573397,已经超出了32位int的最小值范围。PHP 5会自动把这个溢出的结果转为float类型(因为float能容纳更大的数值范围)。 - 当执行
& 0xFFFFFFFF位运算时,PHP会先把这个float转换为对应的无符号32位整数(本质是对数值取模2^32),得到0x791f426b(十进制2032091755),最后转成int赋值给$z12,这就是PHP 5.5返回正确低32位结果的原因。
2. PHP 7的处理逻辑
PHP 7对整数溢出和类型转换做了严格的行为调整:
- 同样,
$z10 + $z11溢出后转为float,但当你尝试把这个超出32位int范围的float强制转换为int时,PHP 7会直接返回0(这是32位环境下的特定行为,目的是明确标记超出范围的转换失败)。 - 不管是
(int)(...)还是后续的& 0xFFFFFFFF位运算,都会先触发这个失败的类型转换,得到0,最终导致$z12和$z的结果都是0。
额外验证:手动计算结果
我们可以手动计算两个十六进制值的和:0xeb9c083c + 0x8d833a2f = 0x1791f426b
取低32位就是0x791f426b,和PHP 5.5的结果完全一致,这说明PHP 5.5正确保留了溢出后的低32位数据,而PHP 7的类型转换规则导致这个数据丢失,返回了0。
内容的提问来源于stack exchange,提问作者Moti
相关产品推荐
相关产品推荐

