Неприятные последствия при переходе с 32-х битной на 64-х битную
- 21.02.12, 08:47
При переходе с 32-х битной на 64-х битную версию PHP выплывает очень неприятный сюрприз - все функции, которые возвращали отрицательное целое число (crc32, ip2long, etc), при тех же данных, будут возвращать положительное число.
Результат работы следующего кода:
?>
На 32х битах = -982057838, на 64х битах = 3312909458, фактически это одно и тоже число - 0хc576fc92, разница только в интерпретации знакового бита. Если это число дальше используется, например для вставки в Mysql (в поле типа signed int), то вместо ожидаемых 2х одинаковых записей мы получим: -982057838 и 2147483647.
Данная особенность связана с тем, что в PHP внутренним представлением целого числа является long, который соответственно на 32х битных системах является 4х байтовым, а на 64х битных 8-ми байтовым. Проблема выплывает из-за того что при выводе данных php использует шаблон вывода "%ld", а знаковым считается 32-й или 64-й бит в зависимости от битности сборки PHP.
Пути решения проблемы:
1) Выставить знаковый бит:
$crc -= 2<<31;
2) При выводе использовать свой шаблон: (s)printf("%d", $crc) или (s)printf("%u", $crc).
3) Использовать 32-х битную версию PHP.
Результат работы следующего кода:
<?php
echo crc32('habrahabr test crc32');?>
Данная особенность связана с тем, что в PHP внутренним представлением целого числа является long, который соответственно на 32х битных системах является 4х байтовым, а на 64х битных 8-ми байтовым. Проблема выплывает из-за того что при выводе данных php использует шаблон вывода "%ld", а знаковым считается 32-й или 64-й бит в зависимости от битности сборки PHP.
Пути решения проблемы:
1) Выставить знаковый бит:
$crc = crc32($num);
if($crc & 0x80000000) $crc -= 2<<31;
3) Использовать 32-х битную версию PHP.


















