perl pack和unpack的使用方法
Pack 与unpack使用说明:
pack可视为将一系列的片段的数值打包在一起,可用于对dev档案、socket、memory的读写,
因为这些需要一块完整的memory,而且需要事先打包成特定格式;
而unpack可以视为将将这些完整的 memory切割计算,取得我们所需要各部分的Variable。
例子如下:
print pack(“H2”x10,map{ “3$_” } (0..9);
得到
0123456789
因为ASCII中30~39代表数字0-9。所以pack后可以得到ascii编码的0->9,
而我们可以利用unpack将string作逆向操作。
print unpack(“H*”,”0123456789”);
30313233343536373839
同样的作法可以用在中文字中,至是你要注意OS的编码格式,UTF-8、GB2312、Big5得到的数值并不会相同。
Pack与unpack也可以用在对于对于固定格式的文件作处理的情形下:
代码:
Date |Description | Income |Expenditure
01/24/2001 Ahmed's Camel Emporium 1147.99
01/28/2001 Flea spray 24.99
01/29/2001 Camel rides to tourists 235.00
看到上面格式,想必大家很多人都用用substr将固定字段中的字符串取出来,
或利用有点点复杂的Regular Expression将上面的文件字段匹配出来,
而实际上我们要将上面字段一个一个匹配出来可以用一行搞定
例子:
while(){
my($date,$desc,$income,$expend) = unpack(“A10xA27xA7xA*”);
}
简单说明:
A10: A表示ASCII,A10表示10个ASCII character,Date的表示就是用10个ASCII码;
x : x表示null byte也等于skip a byte,也就是说我们要跳过一个char(|),
A27: 然后接着27个ASCII char,
x : 然后跳过一个vhar,
A7 : 再接上7个ASCII,
x : 在跳过一个char,
A* : 最后A*表示不管后面char有多少个,全含括进来。
这样子就可以得到各个字段相对应的数据,很简单吧!:) 不需要什么太多的技巧,一行搞定。
之后将income与expend作加总,得到total_income、total_expend,数值,然后再输出的时候,
如果也要格式对称,要怎么办?
大多数人都会用format或sprintf,然后一行一行很辛苦的,将结果输出。
$income = sprintf("%.2f",$income); # Get them into
$expend = sprintf("%.2f",$expend); # "financial" format
其实可以简化成:将$income与$expend先格式化,然后同上例将结果输出:
print pack("A11 A28 A8 A*",$date,"Totals",$expend);
注意:这边多加一个char主要是因为’x’表示的是null byte,所以如果用A7xA27xA7xA*,
则输出的字符串会连在一起,而多给他一个char,就可以让字符串不会都连在一起。
完成程序如下:
#!/usr/bin/perl
use POSIX;
open(FF,"tt.txt");
my ($date,$expend) = unpack("A10xA27xA7xA*",$_);
$tot_income = $income;
$tot_expend = $expend;
$expend = sprintf(".2f","$desc",$expend),"n";
$tot_income = sprintf("%.2f",$tot_income); # Get them into
$tot_expend = sprintf(".2f",$tot_expend); # "financial" format
$date = POSIX::strftime("%m/%d/%Y",localtime);
print pack("A11 A28 A8 A*",$tot_income,$tot_expend),"n";
整数的pack:
对于整数需要注意各个OS所定义的int的长度,与各个OS所用的byte order顺序是little-endian还是big-endian,
就是高位在前还是低位在前的意思。
my $ps = pack(‘s’,20302);
s:a signed short intger,一般都是16bits=2bytes,
如果我们将他print出来(打印这些pack后的字符,实际上是不具任何意义的),
会发现他等于NO或ON,然后将$ps在unpack可以得到20302
unpack(‘s’,’NO’); ----------------->20302
注意:如果今天你用”s”,pack一个大于65535的数字,高位会自动被删除,
而得到与你想要的数字不同的结果,这点需要注意。
“l”: signed 32bits integer
“L”:unsigned 32bits integer
“q”:signed 64bits intger
“Q”:unsigned 64bits integer
“i”:signed integers of “local custom” variety
“I”:unsigned integers of “local custom” variety
这两个”i”与”I”主要与机器的OS定义有关系,其长度等于c中的sizeof(int),
如果要用于perl与其他语言的沟通,最好使用这个编码原则。
对照表:(其中%Config要先use Config;才能使用)
signed unsigned byte length in C byte length in Perl
s! S! sizeof(short) $Config{shortsize}
i! I! sizeof(int) $Config{intsize}
l! L! sizeof(long) $Config{longsize}
q! Q! sizeof(longlong) $Config{longlongsize}
对memory stack作pack:
例子如下:memory stack长得像下面这样,接着利用unpack将stack中的各个字段取出。
--------- ---- ---- ---------
TOS: | IP |TOS 4:| FL | FH | FLAGS TOS 14:| SI |
| CS | | AL | AH | AX | DI |
| BL | BH | BX | BP |
---- ---- ---------
| CL | CH | CX | DS |
| DL | DH | DX | ES |
---- ---- ---------
my( $ip,$cs,$flags,$ax,$bx,$cd,$dx,$si,$di,$bp,$ds,$es ) = unpack( 'v12',$frame );
‘v’ :unsigned short in ‘VAX ‘ order
这是取出横列的IP、CS、FLAGS、AX、BX、CX、DX、SI、DI、BP、DS、ES
my( $fl,$fh,$al,$ah,$bl,$bh,$cl,$ch,$dl,$dh ) =
unpack( 'C10',substr( $frame,4,10 ) );
‘C’:unsign character value,用于bytes读取
这样子分两行很麻烦,所以将他们放在一起得到:
$flags,$fl,helvetica; line-height:18px">$ax,$cx,$dh,helvetica; line-height:18px">$si,$es ) =
unpack( 'v2' . ('vXXCC' x 5) . 'v5',$frame );
‘X’:Backup a byte
网络应用:
‘n’: An unsigned short in "network" (big-endian) order
‘N’: An unsigned long in "network" (big-endian) order
在作网络链接时,往往需要将长度先送给Server,使其知道后面有多少character要读取,
因此如果有一段msg,可以利用下列方式打包:
my $buf = pack( 'N',length( $msg ) ) . $msg;
说明:等于「长度」( unsigned long)加上讯息内容,也可简化为:
my $buf = pack(‘NA*’,length($msg),$msg);
然后将$buf送至对方server。同样对方可用unpack(‘NA*’,$buf)取得送出的数据。
Floating Point Numbers:
‘f’: float (A single-precision float in the native format)
‘d’:double(A double-precision float in the native format)
对于浮点数(float point)可以使用f或d来作pack与unpack动作。
奇特的例子:
Bit Strings:
String中都是0或1,对其作pack/unpack的转换,需要注意那一系列的0/1,
与每八个bit一个字符的顺序性。假设今天有个string等于 ”10001100”可以用下列方式:
$byte = pack( 'B8','10001100' ); # start with MSB
$byte = pack( 'b8','00110001' ); # start with LSB
b A bit string (ascending bit order inside each byte,like vec()).(渐增)
B A bit string (descending bit order inside each byte).(渐减)
如果要对string中的一部份bits作pack/unpack是不可能的,因为pack会从最旁边开始,
然后以8个bits为一组,如果不足八个则补0。
----------------- -----------------
| S Z - A - P - C | - - - - O D I T |
MSB LSB MSB LSB
例子:如上图中「-」表示保留的bit,不使用。
将上列这2 bytes 转换成一个string,可以利用’b16’来作:
#!usr/bin/perl
$status = "1101010100001111";
$ps= pack('b16',$status);
print "$psn";
$status=unpack('b16',$ps);
print "$statusn";
@aa = split(//,helvetica; line-height:18px">print "@aan";
#---简化
#---可取得各个bit的数值
($carry,undef,$parity,$auxcarry,$sign,helvetica; line-height:18px">$trace,$interrupt,$direction,$overflow) =
split( //,unpack( 'b16',$status ) );
如果使用’b12’则,后面的4个bit会被忽略并不会被使用。
Uuencode:(Unix-To-Unix Encode)
如果对于UNIX很熟悉的,应该知道uuencode与uudecode是干什么用的,
他可视为早期UNIX之间互相传送数据,所用的一种编码方法,将文件编码,
以便利于在早期的网络上传送数据,现在很少使用,但是有时还是有人会用到,
编码原理:取出三个bytes,将之切割成6份,每份4个 bits,然后在后面填入x20,
如此直到整个文件编码完成。
Pack可使用’u’作这件事情。
my $uubuf = pack( 'u',$bindat );
计算总和:(Do Sums)
pack中有个特殊的template,%专门用来计算总和的,但是他不能在pack中使用,
而且他只能用于其他数字的前置位置(prefix)。
用于数字时:
my $buf = pack( 'iii',100,20,3 );
print unpack( '2i3',$buf ),"n"; # prints 123
用于字符串时:
print unpack( '2A*',"x01x10" ),"n"; # prints 17
上面两个例子,%会将后面i3、A*加总起来,得到最后结果123与17,这可以用来得到最后的check sum。
另外不要太相信他所得到的数值,因为他们无法保证正确(?)。
用来取得netmask的bits数目:
my $bitcount = unpack( '2b*',$mask );
my $evenparity = unpack( ' *',$mask );
取得evenparity的数值…mask=pack(‘b*’,”11111111111111111…0”);
Unicode:
$UTF8{Euro} = pack( 'U',0x20AC );
欧洲用字编码x20AC,其UTF8的编码字符为$URF{Euro}。
# pack and unpack the Hebrew alphabet
my $alefbet = pack( 'U*',0x05d0..0x05ea );
my @hebrew = unpack( 'U*',$utf );
用于pack/unpack unicode编码
另一种Portable编码:
w A BER compressed integer. Its bytes represent an unsigned integer in base 128,helvetica; line-height:18px">most significant digit first,with as few digits as possible. Bit eight (the high bit)
is set on each byte except the last.
my $berbuf = pack( 'w*',1,128,128 1,128*128 127 );
长度与宽度(Length and Width)
字符串长度(String Length)
在传送网络数据时,往往需要将数据的长度放在封包的标头处,让对方Server知道后续还有多少数据需要处理:
下列例子为两个null terminated字符串加上数据长度,再加上数据,得到最后要送出的数据。
Z:A null terminated (ASCIZ) string,will be null padded.
my $msg = pack( 'Z*Z*CA*',$src,$dst,length( $sm ),$sm );
而要取出数据可以用下列方式:
( $src,$len,$sm ) = unpack( 'Z*Z*CA*',$msg );
但是,如果我们在pack后面加上另一个C,则在unpack时,会无法正确得到数据。
因为A*会把所有的剩余character都抓给$sm,而使得$prio变成无定义。
# pack a message
my $msg = pack( 'Z*Z*CA*C',$sm,$prio );
# unpack fails - $prio remains undefined!
因此可以使用下列方式取得数据:
# pack a message: ASCIIZ,ASCIIZ,length/string,byte
my $msg = pack( 'Z* Z* C/A* C',helvetica; line-height:18px"># unpack
加上”/”符号,可以使得perl在pack A*会记住$sm的长度,然后后续的$prio就可以区别出来储存,
而在unpack时,就可以依照$sm的长度,而将$sm的数据取出,
剩下来的就是$prio的数据。”/”只有在后面接上A*、a*、Z*时有意义。
“/”表示后面A*的长度,占1个byte
“/”可以代表任何数字,用以表示其后A*的长度
# pack/unpack a string preceded by its length in ASCII
my $buf = pack( 'A4/A*',"Humpty-Dumpty" );
# unpack $buf: '13 Humpty-Dumpty'
my $txt = unpack( 'A4/A*',$buf );
“/”在perl 5.6以后才出现,之前版本并不支持。针对旧版本需要做如下修改已取得长度。
my $msg = pack( 'Z* Z* C A* C',length $sm,helvetica; line-height:18px">( undef,$len) = unpack( 'Z* Z* C',$msg );#--先取得长度
#--依照长度设定A的长度
($src,$prio) = unpack ( "Z* Z* x A$len C",helvetica; line-height:18px">Dynamic Template
从前面到现在我们看到的都是有固定长度的范例,但是如果碰到没有固定长度的怎么办?以下有个例子来说明:
my $env = pack( 'A*A*Z*' x keys( %Env ) . 'C',helvetica; line-height:18px">map( { ( $_,'=',$Env{$_} ) } keys( %Env ) ),0 );
为了方便让C来Parsing这个string,所以利用两个string与一个null terminated字符串,
利用map将$ENV中的参数读出来,然后利用(AAA,=,BBB)的方式,
储存成一个array,然后传给pack,然后 pack利用”A*A*Z*将AAA,BBB给打包起来,
keys(%ENV)表示ENV hash总共有多少个$element在里面。最后为了方便C parsing,在最后面加上一个”0”。
my $n = $env =~ tr/// - 1;
my %env = map( split( /=/,$_ ),unpack( 'Z*' x $n,$env ) );
而在unpack时,要先算出$env里面到底有多少个$element在里面,这可以透过tr来计算。
Pack 与unpack使用说明:
pack可视为将一系列的片段的数值打包在一起,可用于对dev档案、socket、memory的读写,
因为这些需要一块完整的memory,而且需要事先打包成特定格式;
而unpack可以视为将将这些完整的 memory切割计算,取得我们所需要各部分的Variable。
例子如下:
print pack(“H2”x10,map{ “3$_” } (0..9);
得到
0123456789
因为ASCII中30~39代表数字0-9。所以pack后可以得到ascii编码的0->9,
而我们可以利用unpack将string作逆向操作。
print unpack(“H*”,”0123456789”);
30313233343536373839
同样的作法可以用在中文字中,至是你要注意OS的编码格式,UTF-8、GB2312、Big5得到的数值并不会相同。
Pack与unpack也可以用在对于对于固定格式的文件作处理的情形下:
代码:
Date |Description | Income |Expenditure
01/24/2001 Ahmed's Camel Emporium 1147.99
01/28/2001 Flea spray 24.99
01/29/2001 Camel rides to tourists 235.00
看到上面格式,想必大家很多人都用用substr将固定字段中的字符串取出来,
或利用有点点复杂的Regular Expression将上面的文件字段匹配出来,
而实际上我们要将上面字段一个一个匹配出来可以用一行搞定
例子:
while(){
my($date,$desc,$income,$expend) = unpack(“A10xA27xA7xA*”);
}
简单说明:
A10: A表示ASCII,A10表示10个ASCII character,Date的表示就是用10个ASCII码;
x : x表示null byte也等于skip a byte,也就是说我们要跳过一个char(|),
A27: 然后接着27个ASCII char,
x : 然后跳过一个vhar,
A7 : 再接上7个ASCII,
x : 在跳过一个char,
A* : 最后A*表示不管后面char有多少个,全含括进来。
这样子就可以得到各个字段相对应的数据,很简单吧!:) 不需要什么太多的技巧,一行搞定。
之后将income与expend作加总,得到total_income、total_expend,数值,然后再输出的时候,
如果也要格式对称,要怎么办?
大多数人都会用format或sprintf,然后一行一行很辛苦的,将结果输出。
$income = sprintf("%.2f",$income); # Get them into
$expend = sprintf("%.2f",$expend); # "financial" format
其实可以简化成:将$income与$expend先格式化,然后同上例将结果输出:
print pack("A11 A28 A8 A*",$date,"Totals",$expend);
注意:这边多加一个char主要是因为’x’表示的是null byte,所以如果用A7xA27xA7xA*,
则输出的字符串会连在一起,而多给他一个char,就可以让字符串不会都连在一起。
完成程序如下:
#!/usr/bin/perl
use POSIX;
open(FF,"tt.txt");
my ($date,$expend) = unpack("A10xA27xA7xA*",$_);
$tot_income = $income;
$tot_expend = $expend;
$expend = sprintf(".2f","$desc",$expend),"n";
$tot_income = sprintf("%.2f",$tot_income); # Get them into
$tot_expend = sprintf(".2f",$tot_expend); # "financial" format
$date = POSIX::strftime("%m/%d/%Y",localtime);
print pack("A11 A28 A8 A*",$tot_income,$tot_expend),"n";
整数的pack:
对于整数需要注意各个OS所定义的int的长度,与各个OS所用的byte order顺序是little-endian还是big-endian,
就是高位在前还是低位在前的意思。
my $ps = pack(‘s’,20302);
s:a signed short intger,一般都是16bits=2bytes,
如果我们将他print出来(打印这些pack后的字符,实际上是不具任何意义的),
会发现他等于NO或ON,然后将$ps在unpack可以得到20302
unpack(‘s’,’NO’); ----------------->20302
注意:如果今天你用”s”,pack一个大于65535的数字,高位会自动被删除,
而得到与你想要的数字不同的结果,这点需要注意。
“l”: signed 32bits integer
“L”:unsigned 32bits integer
“q”:signed 64bits intger
“Q”:unsigned 64bits integer
“i”:signed integers of “local custom” variety
“I”:unsigned integers of “local custom” variety
这两个”i”与”I”主要与机器的OS定义有关系,其长度等于c中的sizeof(int),
如果要用于perl与其他语言的沟通,最好使用这个编码原则。
对照表:(其中%Config要先use Config;才能使用)
signed unsigned byte length in C byte length in Perl
s! S! sizeof(short) $Config{shortsize}
i! I! sizeof(int) $Config{intsize}
l! L! sizeof(long) $Config{longsize}
q! Q! sizeof(longlong) $Config{longlongsize}
对memory stack作pack:
例子如下:memory stack长得像下面这样,接着利用unpack将stack中的各个字段取出。
--------- ---- ---- ---------
TOS: | IP |TOS 4:| FL | FH | FLAGS TOS 14:| SI |
| CS | | AL | AH | AX | DI |
| BL | BH | BX | BP |
---- ---- ---------
| CL | CH | CX | DS |
| DL | DH | DX | ES |
---- ---- ---------
my( $ip,$cs,$flags,$ax,$bx,$cd,$dx,$si,$di,$bp,$ds,$es ) = unpack( 'v12',$frame );
‘v’ :unsigned short in ‘VAX ‘ order
这是取出横列的IP、CS、FLAGS、AX、BX、CX、DX、SI、DI、BP、DS、ES
my( $fl,$fh,$al,$ah,$bl,$bh,$cl,$ch,$dl,$dh ) =
unpack( 'C10',substr( $frame,4,10 ) );
‘C’:unsign character value,用于bytes读取
这样子分两行很麻烦,所以将他们放在一起得到:
$flags,$fl,helvetica; line-height:18px">$ax,$cx,$dh,helvetica; line-height:18px">$si,$es ) =
unpack( 'v2' . ('vXXCC' x 5) . 'v5',$frame );
‘X’:Backup a byte
网络应用:
‘n’: An unsigned short in "network" (big-endian) order
‘N’: An unsigned long in "network" (big-endian) order
在作网络链接时,往往需要将长度先送给Server,使其知道后面有多少character要读取,
因此如果有一段msg,可以利用下列方式打包:
my $buf = pack( 'N',length( $msg ) ) . $msg;
说明:等于「长度」( unsigned long)加上讯息内容,也可简化为:
my $buf = pack(‘NA*’,length($msg),$msg);
然后将$buf送至对方server。同样对方可用unpack(‘NA*’,$buf)取得送出的数据。
Floating Point Numbers:
‘f’: float (A single-precision float in the native format)
‘d’:double(A double-precision float in the native format)
对于浮点数(float point)可以使用f或d来作pack与unpack动作。
奇特的例子:
Bit Strings:
String中都是0或1,对其作pack/unpack的转换,需要注意那一系列的0/1,
与每八个bit一个字符的顺序性。假设今天有个string等于 ”10001100”可以用下列方式:
$byte = pack( 'B8','10001100' ); # start with MSB
$byte = pack( 'b8','00110001' ); # start with LSB
b A bit string (ascending bit order inside each byte,like vec()).(渐增)
B A bit string (descending bit order inside each byte).(渐减)
如果要对string中的一部份bits作pack/unpack是不可能的,因为pack会从最旁边开始,
然后以8个bits为一组,如果不足八个则补0。
----------------- -----------------
| S Z - A - P - C | - - - - O D I T |
MSB LSB MSB LSB
例子:如上图中「-」表示保留的bit,不使用。
将上列这2 bytes 转换成一个string,可以利用’b16’来作:
#!usr/bin/perl
$status = "1101010100001111";
$ps= pack('b16',$status);
print "$psn";
$status=unpack('b16',$ps);
print "$statusn";
@aa = split(//,helvetica; line-height:18px">print "@aan";
#---简化
#---可取得各个bit的数值
($carry,undef,$parity,$auxcarry,$sign,helvetica; line-height:18px">$trace,$interrupt,$direction,$overflow) =
split( //,unpack( 'b16',$status ) );
如果使用’b12’则,后面的4个bit会被忽略并不会被使用。
Uuencode:(Unix-To-Unix Encode)
如果对于UNIX很熟悉的,应该知道uuencode与uudecode是干什么用的,
他可视为早期UNIX之间互相传送数据,所用的一种编码方法,将文件编码,
以便利于在早期的网络上传送数据,现在很少使用,但是有时还是有人会用到,
编码原理:取出三个bytes,将之切割成6份,每份4个 bits,然后在后面填入x20,
如此直到整个文件编码完成。
Pack可使用’u’作这件事情。
my $uubuf = pack( 'u',$bindat );
计算总和:(Do Sums)
pack中有个特殊的template,%专门用来计算总和的,但是他不能在pack中使用,
而且他只能用于其他数字的前置位置(prefix)。
用于数字时:
my $buf = pack( 'iii',100,20,3 );
print unpack( '2i3',$buf ),"n"; # prints 123
用于字符串时:
print unpack( '2A*',"x01x10" ),"n"; # prints 17
上面两个例子,%会将后面i3、A*加总起来,得到最后结果123与17,这可以用来得到最后的check sum。
另外不要太相信他所得到的数值,因为他们无法保证正确(?)。
用来取得netmask的bits数目:
my $bitcount = unpack( '2b*',$mask );
my $evenparity = unpack( ' *',$mask );
取得evenparity的数值…mask=pack(‘b*’,”11111111111111111…0”);
Unicode:
$UTF8{Euro} = pack( 'U',0x20AC );
欧洲用字编码x20AC,其UTF8的编码字符为$URF{Euro}。
# pack and unpack the Hebrew alphabet
my $alefbet = pack( 'U*',0x05d0..0x05ea );
my @hebrew = unpack( 'U*',$utf );
用于pack/unpack unicode编码
另一种Portable编码:
w A BER compressed integer. Its bytes represent an unsigned integer in base 128,helvetica; line-height:18px">most significant digit first,with as few digits as possible. Bit eight (the high bit)
is set on each byte except the last.
my $berbuf = pack( 'w*',1,128,128 1,128*128 127 );
长度与宽度(Length and Width)
字符串长度(String Length)
在传送网络数据时,往往需要将数据的长度放在封包的标头处,让对方Server知道后续还有多少数据需要处理:
下列例子为两个null terminated字符串加上数据长度,再加上数据,得到最后要送出的数据。
Z:A null terminated (ASCIZ) string,will be null padded.
my $msg = pack( 'Z*Z*CA*',$src,$dst,length( $sm ),$sm );
而要取出数据可以用下列方式:
( $src,$len,$sm ) = unpack( 'Z*Z*CA*',$msg );
但是,如果我们在pack后面加上另一个C,则在unpack时,会无法正确得到数据。
因为A*会把所有的剩余character都抓给$sm,而使得$prio变成无定义。
# pack a message
my $msg = pack( 'Z*Z*CA*C',$sm,$prio );
# unpack fails - $prio remains undefined!
因此可以使用下列方式取得数据:
# pack a message: ASCIIZ,ASCIIZ,length/string,byte
my $msg = pack( 'Z* Z* C/A* C',helvetica; line-height:18px"># unpack
加上”/”符号,可以使得perl在pack A*会记住$sm的长度,然后后续的$prio就可以区别出来储存,
而在unpack时,就可以依照$sm的长度,而将$sm的数据取出,
剩下来的就是$prio的数据。”/”只有在后面接上A*、a*、Z*时有意义。
“/”表示后面A*的长度,占1个byte
“/”可以代表任何数字,用以表示其后A*的长度
# pack/unpack a string preceded by its length in ASCII
my $buf = pack( 'A4/A*',"Humpty-Dumpty" );
# unpack $buf: '13 Humpty-Dumpty'
my $txt = unpack( 'A4/A*',$buf );
“/”在perl 5.6以后才出现,之前版本并不支持。针对旧版本需要做如下修改已取得长度。
my $msg = pack( 'Z* Z* C A* C',length $sm,helvetica; line-height:18px">( undef,$len) = unpack( 'Z* Z* C',$msg );#--先取得长度
#--依照长度设定A的长度
($src,$prio) = unpack ( "Z* Z* x A$len C",helvetica; line-height:18px">Dynamic Template
从前面到现在我们看到的都是有固定长度的范例,但是如果碰到没有固定长度的怎么办?以下有个例子来说明:
my $env = pack( 'A*A*Z*' x keys( %Env ) . 'C',helvetica; line-height:18px">map( { ( $_,'=',$Env{$_} ) } keys( %Env ) ),0 );
为了方便让C来Parsing这个string,所以利用两个string与一个null terminated字符串,
利用map将$ENV中的参数读出来,然后利用(AAA,=,BBB)的方式,
储存成一个array,然后传给pack,然后 pack利用”A*A*Z*将AAA,BBB给打包起来,
keys(%ENV)表示ENV hash总共有多少个$element在里面。最后为了方便C parsing,在最后面加上一个”0”。
my $n = $env =~ tr/// - 1;
my %env = map( split( /=/,$_ ),unpack( 'Z*' x $n,$env ) );
而在unpack时,要先算出$env里面到底有多少个$element在里面,这可以透过tr来计算。