pack()和unpack()如何在Ruby中工作

时间:2013-01-12 13:48:44

标签: ruby binary-data ruby-1.9.3 pack unpack

在Ruby中为什么我们需要数组 Packing directive 如何帮助完成此类打包?

我在控制台中运行了一些代码,以查看Array中指令的内容和方式 packing.But输出与每个指令非常相似。然后在核心中它们有何不同?

irb(main):003:0> n = [ 65, 66, 67 ]
=> [65, 66, 67]
irb(main):004:0> n.pack("ccc")
=> "ABC"
irb(main):005:0> n.pack("C")
=> "A"
irb(main):006:0> n.pack("CCC")
=> "ABC"
irb(main):007:0> n.pack("qqq")
=> "A\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x00\
x00\x00\x00"
irb(main):008:0> n.pack("QQQ")
=> "A\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x00\
x00\x00\x00"
irb(main):009:0> n.pack("SSS")
=> "A\x00B\x00C\x00"
irb(main):010:0> n.pack("sss")
=> "A\x00B\x00C\x00"
irb(main):011:0>

现在我可以从控制台看到n.pack("SSS") and n.pack("sss");n.pack("ccc") and n.pack("CCC"); n.pack("qqq") and n.pack("QQQ")提供相同的输出。然后差异在哪里?

并且文档也没有涵盖每个指令在现实生活中如何工作的一些例子。 我也对下面的指令感到困惑,因为我不知道如何测试它们?任何小代码 它们对我也有帮助:

  • S_, S!
  • S> L> Q>
  • S!< I!<
  • L_, L!

1 个答案:

答案 0 :(得分:10)

您正在询问有关计算机如何在内存中存储数字的基本原则的问题。例如,您可以查看这些内容以了解更多信息:

http://en.wikipedia.org/wiki/Computer_number_format#Binary_Number_Representation
http://en.wikipedia.org/wiki/Signed_number_representations

作为示例,请考虑Ss之间的差异;两者都用于打包和解包16位数字,但一个用于有符号整数,另一个用于无符号整数。当您想要将字符串解包回原始整数时,这具有重要意义。

S:16位无符号表示数字0 - 65535(0 - (2 ^ 16-1))
s:16位有符号整数-32768 - 32767( - (2 ^ 15) - (2 ^ 15-1))(一位用于符号)

可以在这里看到差异:

# S = unsigned: you cannot pack/unpack negative numbers
> [-1, 65535, 32767, 32768].pack('SSSS').unpack('SSSS')
=> [65535, 65535, 32767, 32768]   

# s = signed: you cannot pack/unpack numbers outside range -32768 - 32767
> [-1, 65535, 32767, 32768].pack('ssss').unpack('ssss')
=> [-1, -1, 32767, -32768]

所以你看到你必须知道如何在计算机内存中表示数字才能理解你的问题。有符号数字用一位表示符号,而无符号数字不需要这个额外位,但你不能代表负数。

这是数字如何在计算机内存中表示为二进制的基础。

例如,您需要打包的原因是您需要将数字作为字节流从一台计算机发送到另一台计算机(例如通过网络连接)。您必须将整数编号打包为字节才能通过流发送。另一种选择是将数字作为字符串发送;然后你将它们编码并解码为两端的字符串,而不是打包和解包。

或者假设您需要在Ruby的系统库中调用C函数。用C编写的系统库在基本整数(int,uint,long,short等)和C结构(struct)上运行。在调用此类系统方法之前,您需要将Ruby整数转换为系统整数或C结构。在这些情况下,packunpack可用于界定这些方法。


关于附加指令,它们处理如何表示压缩字节序列的字节顺序。请参阅此处有关endianness的含义及其工作原理:

http://en.wikipedia.org/wiki/Endianness

简单来说,它只是告诉包装方法整数应该转换成字节的顺序:

# Big endian
> [34567].pack('S>').bytes.map(&:to_i)
=> [135, 7]   
# 34567 = (135 * 2^8) + 7

# Little endian
> [34567].pack('S<').bytes.map(&:to_i)
=> [7, 135]   
# 34567 = 7 + (135 * 2^8)