5

在 Ruby 中为什么我们需要数组Packing?如何directive帮助做这样的包装?

我在控制台中运行了一些代码,以查看指令在数组打包中的外观和方式。但是每个指令的输出几乎相同。那么在核心上它们有什么不同呢?

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!
4

1 回答 1

17

你在问一个关于计算机如何在内存中存储数字的基本原理的问题。例如,您可以查看这些以了解更多信息:

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

S以和之间的区别为例s;两者都用于打包和解包 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可以用来接口哪些这样的方法。


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

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)
于 2013-01-12T14:18:14.270 回答