PHP un 64 biti
Es, šķiet, pirmo reizi mūžā šodien saskāros ar problēmu, kuras sakne ir tanī, ka 32bit sistēmas un 64bit sistēmas ir ne pārāk viegli savietojamas.
Eksistē maģiska funkcija, kā unpack()
. Konkrētajā gadījumā man no četriem secīgiem baitiem nepieciešams "izpakot" 32 bitu naturālu skaitli big endian baitu secībā. Nekādu problēmu. Neskatoties ne uz ko, tas vienmēr ir izdevies bez problēmām. Šodien, uz kādas 64 bitu sistēmas radās nepieciešamība palaist attiecīgo skriptu nevis zem PHP4, kā līdz šim, bet nu jau zem PHP5 (uz 32bit PHP5 problēmu nav). Un tad nu sākās.
list(,$command_id) = unpack('N', \ chr(0x80) . chr(0x00) . chr(0x00) . chr(0x09)); # Iegūstam -2147483639
Tas nekas, ka reāli tas ir negatīvs skaitlis, neskatoties uz unpack
norādīto informāciju. Sekojošais kods visu noliek savās vietās un iegūstam pozitīvu skaitli:
$command_id = hexdec(dechex($command_id)); # Iegūstam 2147483657
Taču, uz 64bit PHP5 man šāda operācija pēkšņi sāka izsniegt skaitli 1.8446744071562E+19
. Neiedziļinoties detaļās - kāpēc tā, sapratu, ka esmu nepareizi darījis. Tā vietā, lai atrisinātu problēmu ar pirmo atrasto metodi, man vajadzēja to saprast līdz saknei un risināt ar pirmo pareizo. Un tā būtu:
$command_id &= 0xffffffff;
Šis atrisina problēmu uz 64bit sistēmām, un neko nesalauž uz 32bit. Kā jau minēju, uz tās pašas kastes PHP4 uzvedās korekti.
Taai
2009. gada 4. martā, plkst. 19:47
Bet uzmanies un ņem vērā, ka dechex un hexdec funkcijām ir skaitļa limits - 4294967295 !
binary
2009. gada 4. martā, plkst. 21:56
Taai, droši zini, ka 4294967295? PHP nesupporto unsigned integerus.
binary
2009. gada 4. martā, plkst. 21:58
brr... tikko pamēģināju uz 32bit windas paskatīties, ko PHP teiks par echo 4294967295-1, echo 4294967295+1, ... works like a charm
binary
2009. gada 4. martā, plkst. 22:02
nevermind. pieleca viss.
bubu
2009. gada 4. martā, plkst. 22:35
Problēma ir src/ext/standard/pack.c failā. Tur jāizmet ārā 790 rinda. Un arī 793. rinda, jo "V" arī ir unsigned. Un jāpielabo 788. rindu, lai "L" arī neuzstāda issigned mainīgo, jo "L" arī ir unsigned. unsigned short'iem gan tur par brīnumu source viss ir korekti.
Tur vispār viss ir dīvaini. Izrādās "i" un "I" nebūs 8 baiti uz x86-64, jo tur tiek lietots sizeof(int) izmērs - un tas arī x86-64 ir 4 baiti. Diezgan dīvaini. Jo kautkas cits tas ir tikai DOS'ā (2 baiti) vai kautkādās embedded sistēmās, kur diez vai php ir vajadzīgs. Tāda tipa kā sizeof(long) vai sizeof(void*), kuri tiešām atšķirtos starp x86 un x86-64, tur nemaz nav.
Dīvains tas php ir... Tādā ziņā pitonā ir daudz konsistentāk šitā pakošana un atpakošana saistībā ar C tipiem (int, long, ..).
noisex
2009. gada 5. martā, plkst. 23:31
uz tas sistemas, kur izmantoju unpack/ord/hexdec utt kombinacijas stav uz 32bit os..nevaru notestet. bet nu prikola pec varetu pamegjinat.