今天在弄这个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 |
a | NUL-padded string |
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