Ruby:为啥 unpack('Q') 给出的结果与手动转换不同?
Posted
技术标签:
【中文标题】Ruby:为啥 unpack(\'Q\') 给出的结果与手动转换不同?【英文标题】:Ruby: Why does unpack('Q') give a different result than manual conversion?Ruby:为什么 unpack('Q') 给出的结果与手动转换不同? 【发布时间】:2018-04-29 09:28:05 【问题描述】:我正在尝试编写一个函数,该函数将 .unpack('Q')
(解压缩到 uint64_t)而不访问解压缩方法。
当我手动从字符串转换为二进制到 uint64 时,我得到的结果与 .unpack('Q')
不同:
Integer('abcdefgh'.unpack('B*').first, 2) # => 7017280452245743464
'abcdefgh'.unpack('Q').first # => 7523094288207667809
我不明白这里发生了什么。
我也不明白为什么.unpack('Q')
的输出不管输入的大小都是固定的。如果我在 'abcdefgh' 之后添加一千个字符然后 unpack('Q') 它,我仍然只是得到[7523094288207667809]
?
【问题讨论】:
因为指令不同。如果你这样做'abcdefgh'.unpack('C*').pack('c*')
我会得到同样的结果。但是,如果您将其转换为不同位长度的字符,您将获得不同的位变量存储在您的操作系统中。但本质上它们是相同的。
试试这个,'abcdefgh'.unpack('C*').pack('Q*')
。您将得到不同的结果,即 64 位。
我选择C*
,因为它返回二进制值而不是它的string representation。
【参考方案1】:
字节顺序很重要:
Integer('abcdefgh'.
each_char.
flat_map |c| c.unpack('B*') .
reverse.
join, 2)
#⇒ 7523094288207667809
'abcdefgh'.unpack('Q*').first
#⇒ 7523094288207667809
您的代码产生了错误的结果,因为在转换为二进制后,bytes should be reversed。
对于您问题的最后一部分,.unpack('Q')
的输出不会随着更长的输入字符串而改变的原因是因为格式指定了单个 64 位值,因此前 8 个字符之后的任何字符都将被忽略。如果您指定了Q2
的格式和一个 16 个字符的字符串,您将解码 2 个值:
> 'abcdefghihjklmno'.unpack('Q2')
=> [7523094288207667809, 8029475498074204265]
你会再次发现添加额外的字符不会改变结果:
> 'abcdefghihjklmnofoofoo'.unpack('Q2')
=> [7523094288207667809, 8029475498074204265]
Q*
的格式将返回与输入中 64 位的倍数一样多的值:
> 'abcdefghihjklmnopqrstuvw'.unpack('Q*')
=> [7523094288207667809, 8029475498074204265, 8608196880778817904]
> 'abcdefghihjklmnopqrstuvwxyz'.unpack('Q*')
=> [7523094288207667809, 8029475498074204265, 8608196880778817904]
【讨论】:
这是一个很好的答案!我没有发布单独的答案,而是添加了一些示例来涵盖问题的最后一部分,并将@987654329@ 替换为each_char
,感觉更清晰一些。希望这没问题。
谢谢!我以为我试过了,但我想我一定是不小心颠倒了位而不是颠倒了字节。以上是关于Ruby:为啥 unpack('Q') 给出的结果与手动转换不同?的主要内容,如果未能解决你的问题,请参考以下文章
@,x,X 指令如何与 Ruby pack()/unpack() 方法一起使用?
为啥不能以 unpack("Lfffffff",$bytes) 的形式将许多 unpack 语句压缩为一个?
为啥函数在 php 中以 @ 开头?像@unpack(xxx)? [复制]