这个问题是超级用户的migrated,因为昨天可以在Stack Overflow.Migrated上回答。我一直认为Perl中的pack和unpack在某种意义上是相反的。但是,第二个命令什么也不打印。为什么?
pack
unpack
$ perl -le 'print unpack("N", 127.0.0.1)' 2130706433 $ perl -le 'print pack("N", 2130706433)' nothing is here
8dtrkrch1#
不,它打印了四个字节-没有一个碰巧是“可见的”ASCII字符,但它们正好对应于127.0.0.1的原始值:
127.0.0.1
$ perl -le 'print pack("N", 2130706433)' | hexdump -C 00000000 7f 00 00 01 0a |.....| 00000005
如果您尝试不使用pack/unpack打印此值,您将获得完全相同的结果:
$ perl -le '$a = 127.0.0.1; print $a' | hexdump -C 00000000 7f 00 00 01 0a |.....| 00000005
这里的问题是127.0.0.1和"127.0.0.1"不是一回事,它是一个Perl特定的“版本字符串”文字,* 已经 * 存储为压缩字节串,相当于"\x7f\x00\x00\x01"。
"127.0.0.1"
"\x7f\x00\x00\x01"
zu0ti5jz2#
是的,它们是彼此的逆。
pack "N"
unpack "N"
对于有效输入,以下情况为真:
unpack( "N", pack( "N", $x ) ) == $x
pack( "N", unpack( "N", $x ) ) eq $x
127.0.0.1是v127.0.0.1的缩写。它们被称为版本字符串或“v”字符串。以下是等效的:
v127.0.0.1
pack "C*", split /\./, "127.0.0.1"
chr( 127 ) . chr( 0 ) . chr( 0 ) . chr( 1 )
"\x7F\x00\x00\x01"
所有这些都产生一个四字节的字符串,由值127、0、0和1组成。值得注意的是,127.0.0.1 * 不 * 等价于"127.0.0.1"。您希望inet_ntoa或inet_ntop获得字符串127.0.0.1,而不是unpack "N"。生成的字符串中没有一个字符是可打印的,这就是为什么在打印它们时得到“nothing”的原因。我将使用od来更好地了解打印的内容。
inet_ntoa
inet_ntop
od
$ perl -e'print 127.0.0.1' | od -t x1 0000000 7f 00 00 01 0000004 $ perl -le'print unpack( "N", 127.0.0.1 )' 2130706433 $ perl -e'print pack( "N", 2130706433 )' | od -t x1 0000000 7f 00 00 01 0000004
正如您所看到的,unpack确实像预期的那样反转了pack。
f87krz0w3#
正如@user1686已经说过的,您将得到一个“机器”编号--一个表示该编号的位模式。要处理IP号码,您可以使用Socket的inet_aton(ASCII到数字)或inet_ntoa(相反):
Socket
inet_aton
% perl -MSocket=inet_aton -le 'print unpack q(N), inet_aton(shift)' 127.0.0.1 % perl -MSocket=inet_ntoa -le 'print inet_ntoa(pack q(N), shift)' 2130706433
请注意,在Perl中,文字代码127.0.0.1是历史的一个奇怪的怪癖。这是一种语义版本控制风格“数字”。它会自动打包自己,这就是为什么你的unpack可以工作。如果你有一个文字版本号,这没有什么错,但它不会对字符串起作用。
% perl -le 'print 127.1.0.0' | hexdump -C 00000000 7f 01 00 00 0a |....| 00000004 % perl -le 'print pack q(C*), 127,1,0,0' | hexdump -C 00000000 7f 01 00 00 0a |.....| 00000005
3条答案
按热度按时间8dtrkrch1#
不,它打印了四个字节-没有一个碰巧是“可见的”ASCII字符,但它们正好对应于
127.0.0.1
的原始值:如果您尝试不使用pack/unpack打印此值,您将获得完全相同的结果:
这里的问题是
127.0.0.1
和"127.0.0.1"
不是一回事,它是一个Perl特定的“版本字符串”文字,* 已经 * 存储为压缩字节串,相当于"\x7f\x00\x00\x01"
。zu0ti5jz2#
是的,它们是彼此的逆。
pack "N"
将值编码为32位的大端无符号整数。unpack "N"
将32位大字节无符号整数解码为值。对于有效输入,以下情况为真:
unpack( "N", pack( "N", $x ) ) == $x
pack( "N", unpack( "N", $x ) ) eq $x
127.0.0.1
是v127.0.0.1
的缩写。它们被称为版本字符串或“v”字符串。以下是等效的:127.0.0.1
v127.0.0.1
pack "C*", split /\./, "127.0.0.1"
chr( 127 ) . chr( 0 ) . chr( 0 ) . chr( 1 )
"\x7F\x00\x00\x01"
所有这些都产生一个四字节的字符串,由值127、0、0和1组成。
值得注意的是,
127.0.0.1
* 不 * 等价于"127.0.0.1"
。您希望inet_ntoa
或inet_ntop
获得字符串127.0.0.1
,而不是unpack "N"
。生成的字符串中没有一个字符是可打印的,这就是为什么在打印它们时得到“nothing”的原因。我将使用
od
来更好地了解打印的内容。正如您所看到的,
unpack
确实像预期的那样反转了pack
。f87krz0w3#
正如@user1686已经说过的,您将得到一个“机器”编号--一个表示该编号的位模式。
要处理IP号码,您可以使用
Socket
的inet_aton
(ASCII到数字)或inet_ntoa
(相反):请注意,在Perl中,文字代码
127.0.0.1
是历史的一个奇怪的怪癖。这是一种语义版本控制风格“数字”。它会自动打包自己,这就是为什么你的unpack
可以工作。如果你有一个文字版本号,这没有什么错,但它不会对字符串起作用。