今天在弄這個pack方法,但是真不知道如何寫下來,感覺很紛亂
pack--壓縮資料到位字串之中。
文法:string pack(string format, mixed [args]...);
參數一:format參數表示資料用什麼方式讀取到
參數二:將要壓縮的資料。
參數一 的種類
a 將字串空白以 NULL 字元填滿
A 將字串空白以 SPACE 字元 (空格) 填滿
h 十六進位字串,低位在前
H 十六進位字串,高位在前
c 有號字元
C 無號字元
s 有號短整數 (十六位,依電腦的位順序)
S 無號短整數 (十六位,依電腦的位順序)
n 無號短整數 (十六位, 高位在後的順序)
v 無號短整數 (十六位, 低位在後的順序)
i 有號整數 (依電腦的順序及範圍)
I 無號整數 (依電腦的順序及範圍)
l 有號長整數 (卅二位,依電腦的位順序)
L 無號長整數 (卅二位,依電腦的位順序)
N 無號短整數 (卅二位, 高位在後的順序)
V 無號短整數 (卅二位, 低位在後的順序)
f 單精確浮點數 (依電腦的範圍)
d 倍精確浮點數 (依電腦的範圍)
x 空位
X 倒回一位
@ 填入 NULL 字元到絕對位置
上面參數一得總結來自於網路,不知道是哪個翻譯翻得,總之我個人不推薦看。下面是php手冊上面的內容(全英文的,雖然我也看不懂,但是一個單詞一個單詞的翻譯去理解,也比看上面的翻譯強)
a -- NUL-padded string
A -- SPACE-padded string
h -- Hex string, low nibble first
H -- Hex string, high nibble first
c -- signed char
C -- unsigned char
s -- signed short (always 16 bit, machine byte order)
S -- unsigned short (always 16 bit, machine byte order)
n -- unsigned short (always 16 bit, big endian byte order)
v -- unsigned short (always 16 bit, little endian byte order)
i -- signed integer (machine dependent size and byte order)
I -- unsigned integer (machine dependent size and byte order)
l -- signed long (always 32 bit, machine byte order)
L -- unsigned long (always 32 bit, machine byte order)
N -- unsigned long (always 32 bit, big endian byte order)
V -- unsigned long (always 32 bit, little endian byte order)
f -- float (machine dependent size and representation)
d -- double (machine dependent size and representation)
x -- NUL byte
X -- Back up one byte
@ -- NUL-fill to absolute position
====================H 和 h========================
-------------------------H -- h ------------------------------
先看中文翻譯
H 十六進位字串,高位在前
h 十六進位字串,低位在前
再看英文
h -- Hex string, low nibble first 十六進位,低位在前以半位元組為單位(上面的翻譯少了半位元組,這個半位元組很重要,nibble就是半位元組的意思)
H -- Hex string, high nibble first 十六進位,高位在前以半位元組為單位
H是一次是4位的讀取,一個十六位進位是佔4位,所以H是一次4位,H2是一次8位(即一個位元組)。
echo pack("H",0x4);
echo pack("H2",65);
echo pack("H2",0x41);
echo pack("H2",”41“);
echo pack("H2H2", 0x41, 0x42);
echo pack("h2h2", 0x41,0x42); `
echo pack("H3", 124);
echo pack("h3",124);
輸出如下
@
e
e
A
ef
Vf
//第一行:pack("H",0x4);將一個十六進位(4位)以十六進位的方式讀取然後寫入到字串中。因為0x4是4位,
0x4轉化為十進位為4。而一個位元組是8位,所以會自動補充位一個位元組8位的長度,後面4位補充為0000(記住。但凡要進行pack方法的H前,必須先將位元組補充完整)。所以十進位為40(為什麼要轉化為十進位去在讀取,我也不知道,可能pack方法開發人員就是這麼寫的),十進位40以H十六進位的方式讀取,就是0x40,轉換成ascii碼就為@。
//第二行:pack("H2",65);65是十進位(H預設是讀取讀取十進位,以十六進位的方式讀取),所以65被H後為0x65,轉化為ascii碼就是e。
//第三行:pack("H2",0x41);0x41是十六進位,H2表示一次讀取8位(H預設是讀取讀取十進位,以十六進位的方式讀取),0x41轉化為十進位為65,65被H後為0x65,轉化為ascii碼就是e。
//第四行:pack("H2",”41“);"41"為字串,H2表示讀取1個8位,但是(H預設是讀取讀取十進位,以十六進位的方式讀取,所以字串41就被H預設轉換為十進位41),十進位41被H後為0x41,轉化為ascii碼就是A。
//第五行:pack("H2H2", 0x41, 0x42);0x41和0x42一共是十六位,H2H2表示讀取兩個8位,轉化為十進位為65和66,65被H後就是0x65,66被H就是0x66,轉化為ascii碼就是分別是ef。
//第六行:pack("h2h2", 0x41,0x42);0x41和0x42是兩個八位,h十六進位字串,低位在前。h和H是幾乎是一樣的只是一個前後排序的問題。H是高位在前,h是低位在前。0x41和0x42轉化為十進位65和66,。這裡讀取後跟H不一樣,h是低位在前,H是高位在前。這裡來做一個比較,如下:
讀取前十六進位 0x41 0x42
讀取前十進位 65 66
H讀取後十六進位 0x65 0x66
h讀取後十六進位 0x56 0x66
H讀取後二進位 01100101 01100110 高位在前 以一次H讀取對象為基礎,4位為單位,進行高低互換
h讀取後二進位 01010110 01100110 低位在前 以一次h讀取對象為基礎,4位為單位,進行高低互換
h按16進位讀取後分別為二進位01010110和01100110轉化為十六進位56和66,轉化為ascii碼為Vf。
//第七行:pack("H3", 124);因為要首先要將位元組補充完整,因此補充完整後為1240。1240是十進位(H預設是讀取讀取十進位,以十六進位的方式讀取),所以1240被H以後打到的是0x1240,轉換為2進位的話就為0001 0010 0100 0000,轉換為16進位就是0x1240,而瀏覽器這裡是以ascii碼讀取的,所以是8位一次的翻譯,所以0x1240被分割成0x12和0x40,0x40是@,0x12在ascii表裡可以看到是(device control 2) 裝置控制2,這個東西在ie8中顯示出來就是上下雙向箭頭。而在ie6,ie7瀏覽器上因為使用的不同的編碼方式,而顯示出不同的字元。
//第八行:pack("h3",124);因為h是低位在前,而且又是1個半位元組(記住。但凡要進行pack方法的H前,必須先將位元組補充完整),然後再,我們來對比一下h與H,
讀取前十六進位 0x7C
讀取前十進位 1240
H讀取後十六進位 0x1240
h讀取後十六進位 0x0421
H讀取後二進位 0001001001000000 高位在前 以一次H讀取對象為基礎,4位為單位,進行高低互換
h讀取後二進位 0000010000100001 低位在前 以一次h讀取對象為基礎,4位為單位,進行高低互換
0000 0100 0010 0001 或者 0x0421,分成0x04和0x21,在ie8中以ascii碼錶示出來就是如上所示
=================V 和 N====v 和 n=======================
-------------------------V - N-----------------------
先看中文翻譯
V 無號短整數 (卅二位, 低位在後的順序)
N 無號短整數 (卅二位, 高位在後的順序)
再看英文
V -- unsigned long (always 32 bit, little endian byte order) 無符號長整型(總是32位,低地址存放最低有效位元組)(根據金山詞霸的解釋)
N -- unsigned long (always 32 bit, big endian byte order) 無符號長整形(總是32位,高地址存放最低有效位元組)(根據金山詞霸的解釋)
下面解釋 little endian 和 big endian
big endian -- 是指低地址存放最高有效位元組
little endian -- 是指低地址存放最低有效位元組
比如:a = 0x05060708
0x05060708
高端<---低端
在BIG-ENDIAN的情況下存放為:
因為低端地址存放高端有效字,08是最低有效字放在高端地址
位元組號 0 1 2 3 ··· ···
低端地址 高端地址
----------------------------------------->
資料 05 06 07 08 ··· ···
在LITTLE-ENDIAN的情況下存放為:
因為低地址存放最低有效位元組,08是最低有效字放在低端地址
位元組號 0 1 2 3 ··· ···
低端地址 高端地址
----------------------------------------->
資料 08 07 06 05 ··· ···
因為記憶體都是從低端地址讀起,因為讀取記憶體資料一般使用地址指標,讀一個地址在加一個位移量。所以這個記憶體little-endian 與 big-endian 決定了資料讀取出來的順序,並不是想上面那個中文翻譯的那樣子(什麼低位在後的順序,我是服了,翻譯的真讓我受不了)。
下面舉幾個V的例子
echo "1 ".pack("V",0x65666768696A6B);echo "<br />";
echo "2 ".pack("V",0x666768696A6B6C);echo "<br />";
echo "3 ".pack("V",0x6768696A6B6C6D);echo "<br />";
顯示出來為
// kjih 01101011 01101010 01101001 01101000
// k j i h
// lkji 01101100 01101011 01101010 01101001
// l k j i
// mlkj 01101101 01101100 01101011 01101010
// m l k j
N的例子
echo "4 ".pack("N",0x65666768696A6B);echo "<br />";
echo "5 ".pack("N",0x666768696A6B6C);echo "<br />";
echo "6 ".pack("N",0x6768696A6B6C6D);echo "<br />";
顯示出來為
// hijk 01101000 01101001 01101010 01101011
// h i j k
// ijkl 01101001 01101010 01101011 01101100
// i j k l
// jklm 01101010 01101011 01101100 01101101
// j k l m
-------------------v - n----------------
先看中文翻譯
v 無號短整數 (十六位, 低位在後的順序)
n 無號短整數 (十六位, 高位在後的順序)
再看英文
v -- unsigned short (always 16 bit, little endian byte order) 無符號短整型(總是16位,低地址存放最低有效位元組)(根據金山詞霸的解釋)
n -- unsigned short (always 16 bit, big endian byte order) 無符號短整形(總是16位,高地址存放最低有效位元組)(根據金山詞霸的解釋)
不用舉例子了,這個跟V和N的區別就是16位和32位的區別。
-------------------關於V - N溢出的問題--------------------------
================ a ===================
先看中文翻譯
a 一個填充空的位元組串
再看英文翻譯
a NUL - padded string
下面是例子:
echo pack("a",65)."<br />";
echo pack("a2",65)."<br />";
echo pack("a2",65,66)."<br />";
echo pack("a2a2",65,66)."<br />";
echo pack("a","65")."<br />";
echo pack("a2","65")."<br />";
echo pack("a",0x65)."<br />";
echo pack("a1",0x65)."<br />";
echo pack("a2",0x65)."<br />";
echo pack("a3",0x65)."<br />";
輸出為:
6
65
"報錯"
65
6
65
1
1
10
101
由上面例子可知,這個該死的a,是以十進位的方式讀取的,不管是字元還是十六進位都是先轉換為十進位讀取的,a1是讀取一位十進位(也不知道是多少位),a2是讀取二位十進位(也不知道是多少位),a3是讀取三位十進位(也不知道是多少位)。如果是十六進位,就先轉換成十進位,如上面的0x65轉換成101,然後用a3讀取後顯示出來就是101。
-------------------------------------------------------------------------------------------------------
echo pack("cccc", 0x41, 0x42, 0x43, 0x44); // ABCD
echo pack("cccc", 65, 66, 67, 68); // ABCD
echo pack("c4", 0x41, 0x42, 0x43, 0x44); // ABCD
echo pack("c4", 65, 66, 67, 68); // ABCD