How the @,x,X directives work with Ruby pack()/unp

2019-05-17 21:06发布

问题:

I just went through the Ruby Doc. But there is no sufficient code to understand how the below three are used in Real life programming:

@,X,x.

can anyone explain it with a simple snippet?

Thanks

回答1:

I will give you few example and will be learning together with you:

[1,2,3,4].pack("CCCC")
=> "\x01\x02\x03\x04"

So serializes in unsigned chars. Every letter in new byte.

[1,2,3,4].pack("CCXCC")
=> "\x01\x03\x04"
[1,2,3,4].pack("CCXXC")
=> "\x03"

Think of the 'X' as backspace directive

[1,2,3,4].pack("CCxC")
=> "\x01\x02\x00\x03"
[1,2,3,4].pack("CCxxC")
=> "\x01\x02\x00\x00\x03"

'x' places zero valued byte.

[1,2,3,4].pack("CC@C")
=> "\x01\x03"
[1,2,3,4].pack("CC@@C")
=> "\x01\x03"
[1,2,3,4].pack("CC@@CC")
=> "\x01\x03\x04"
[1,2,3,4].pack("CC@CC")
=> "\x01\x03\x04"
[1,2,3,4].pack("CC@C@C")
=> "\x01\x04"
[1,2,3,4].pack("CC@C@@C")
=> "\x01\x04"

'@' seems to be a single backspace, but will not support multiple operations at one time. The last one as explanation does not relate at all with the text from the documentation:

@ Moves to absolute position

But is what it seems to be doing.

EDIT BTW @ seems a lot more logical when looked in the context of unpack:

[1,2,3,4,5].pack("CCCCC").unpack("CCC@CCCCC@CC")
=> [1, 2, 3, 1, 2, 3, 4, 5, 1, 2]

Starts unpacking from the very beginning once more.

EDIT2 And here goes the explanation of the other two directives in the context of unpacking:

[1,2,3,4,5].pack("CCCCC").unpack("CCCXC")
=> [1, 2, 3, 3]
[1,2,3,4,5].pack("CCCCC").unpack("CCCXXC")
=> [1, 2, 3, 2]
[1,2,3,4,5].pack("CCCCC").unpack("CCCxC")
=> [1, 2, 3, 5]

So 'x' ignores the next to decode byte and 'X' will make the previous byte the next to read once more. 'X' can stack.

Here goes my first attempt of summarizing the results:

pack:

  • 'x' places zero byte
  • 'X' works like backspace directive, meaning the previous byte is not going to be packed actually
  • '@' has unexplainable behaviour for me

unpack:

  • 'x' Skips the next byte that was for unpacking
  • 'X' moves the reader backwards, meaning the last read byte will be read once more.
  • '@' moves the reader to the very beginning. That means that all the bytes will be unpacked once more.

NOTE Reader is a word I made up for ease of explanation and is, by no means, formal.

EDIT3 Here goes the explanation of "\x01" notation too:

a = [17, 22, 31]
=> [17, 22, 31]
a.pack("CCC")
=> "\x11\x16\x1F"

It seems like this stands for hexadecimal representation. And all the site I have linked to use decimal representation apparently. Otherwise, as it can be seen those are the hexadecimal representations of the given numbers.