php 的pack方法 - Go语言中文社区

php 的pack方法


 

今天在弄这个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

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/zhuoxiong/article/details/7362179
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-08 14:33:12
  • 阅读 ( 616 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢