上周末,我为我的网站更改了虚拟主机。我使用的主机服务器是 32 位操作系统,而我移动到的主机服务器是 64 位。出乎意料的是,我的一些 PHP 脚本开始给出不正确的结果。
在我的例子中,<< 和 >>(位移)操作是罪魁祸首。我最终不得不用 0xFFFFFFFF 掩盖结果,然后如果结果为负,则更改结果以使其像以前一样工作。
我应该在我的 PHP 脚本中寻找任何其他可能的问题吗?
上周末,我为我的网站更改了虚拟主机。我使用的主机服务器是 32 位操作系统,而我移动到的主机服务器是 64 位。出乎意料的是,我的一些 PHP 脚本开始给出不正确的结果。
在我的例子中,<< 和 >>(位移)操作是罪魁祸首。我最终不得不用 0xFFFFFFFF 掩盖结果,然后如果结果为负,则更改结果以使其像以前一样工作。
我应该在我的 PHP 脚本中寻找任何其他可能的问题吗?
它是一种高级语言,因此任何与位无关的(按位运算符、位移位)都是相同的。
整数可能是 64 位而不是 32 位。在一些奇怪的情况下,这可能会导致问题。
位操作需要特别小心才能在系统/架构之间进行移植。
在 C 中,<< 和 >> 操作可以通过使用无符号变量来实现可移植性,这消除了负数的一/二补码规则。
作为一般规则,不要使用固定长度的掩码进行位操作(如 & 和 |)。这些是依赖于架构的。
例如。重置最后 4 位:掩码 0xF0 将适用于 8 位架构,但不适用于 16 位。结果会有所不同(16 位可能有其他未包含在掩码中的位设置)。
要克服这个问题,请使用 ~ 运算符。掩码 ~0xF 等价于 0xF0,但适用于任何架构。除最后 4 位外的所有位都将被重置
strtotime 在 64 位上表现不同。来自 PHP.net:
笔记:
时间戳的有效范围通常是从 1901 年 12 月 13 日星期五 20:45:54 UTC 到 2038 年 1 月 19 日星期二 03:14:07 UTC。(这些日期对应于 32 位有符号整数的最小值和最大值。)此外,并非所有平台都支持负时间戳,因此您的日期范围可能限制为不早于 Unix 纪元。这意味着例如 1970 年 1 月 1 日之前的日期将不适用于 Windows、某些 Linux 发行版和一些其他操作系统。PHP 5.1.0 和更新的版本克服了这个限制。
对于 64 位版本的 PHP,时间戳的有效范围实际上是无限的,因为 64 位可以在任一方向上代表大约 2930 亿年。
We had code that was doing strtotime('0000-00-00') and expected the result to be false, when we moved to 64 bit we got back a negative integer.
当您依赖 32 位二进制数据表示时,您会看到唯一的问题。主要是因为 PHP 使用有符号整数,您会在散列、密钥生成等方面看到问题......当使用 (int) 显式转换为 int 时,数字 > 2^32 将换行,因为它们不会在 64 位环境中换行当然,除非它们 > 2^64。
4 与 8 位示例:
十进制值问题:
0010 >> 1 = 0001 [ 1 dec ]
0000 0010 >> 1 = 0000 0001 [ 1 dec ]
这些都产生相同的结果(十进制),但是:
0100 << 1 = 1000 [ -8 dec ]
0000 0100 << 1 = 0000 1000 [ 16 dec ]
包装问题:
1000 << 1 = 0000 [ 0 dec ]
0000 1000 << 1 = 0001 0000 [ 32 dec ]
所有整数/浮点运算都将被视为 64 位值,因此如果您的最终结果依赖于 32 位块,您将不得不对此进行补偿。
提高到64位会影响浮点除法的结果;因此,如果您的代码执行了一些愚蠢的操作,例如将浮点除法的结果与硬编码常量进行比较,那么预计它会中断。