PHP: pack/unpack補遺

pack/unpack的介紹和使用加上這篇就第三篇了。確實知識點比較多,這篇算是收尾之做吧。仔細去文檔上看pack/unpack的格式化字符說明,就會發現s, S, i, I, l, L, f, d都沒有對應的大端序和小端序的格式化字符,因此有須要的時候必須本身實現。這個真不知道PHP開發項目組是怎麼想的!php

並且確實有人在stackoverflow上這麼問了,詳見:php-pack-format-for-signed-32-int-big-endian 。stackoverflow上的答案比較巧妙,因此我在這裏進行借鑑。shell

L表示無符號長整型,按主機字節序。N表示無符號長整型,大端序。它們都是32位的,因此若是用L和N對同一個整數進行打包,若是結果相等,則本機字節序就是大端序,不然就是小端序。代碼以下:函數

<?php
define('BIG_ENDIAN', pack('L', 1) === pack('N', 1));

if (BIG_ENDIAN)
{
	echo "大端序";
}
else
{
	echo "小端序";
}

echo "\n";

$ php -f test.php
小端序

大端序和小端序事實上是相反的字節序,好比要實現無符號短整型的大端序和小端序,能夠用s格式化字符先進行打包,再判斷大小端來決定是否須要反轉字符串,代碼以下:spa

<?php
define('BIG_ENDIAN', pack('L', 1) === pack('N', 1));

// 有符號16位整型大端序
function pack_int16s_be($num)
{
	if (BIG_ENDIAN)
	{
		return pack("s", $num);
	}

	return strrev(pack("s", $num));
}

// 有符號16位整型小端序
function pack_int16_le($num)
{
	if (BIG_ENDIAN)
	{
		return strrev(pack("s", $num));
	}

	return pack("s", $num);
}

其它幾個也是相似如此實現。可是須要注意的是還須要實現相應版本的unpack,可參考我以前的一篇文章:PHP: chr和pack、unpack那些事.net

對於實現這幾個函數倒不是難事,但在實際打包解包的時候就比較麻煩了。pack還比較好,只是分開打包,再做字符串鏈接。可是對unpack來講,須要根據協議長度,將字節流拆分而後分別解包,確實有點坑。code

本篇文章基本上也就這些知識點,pack/unpack就告一段落了,歡迎你們一塊兒交流~orm

相關文章
相關標籤/搜索