atypic has asked for the wisdom of the Perl Monks concerning the following question:

Hello brethen, I am working on decoding a network packet using perl-- however, unpack puzzles me and I fear I have a lack of understanding about this function.

First of all-- why does this  printf("%d\n", unpack ("h", "F")); produce '6' on my system? Is it because the string "F" is treated as a blob of binary data and therefore this does not really make sense? If so, then should not  printf("%d\n", unpack ("h", pack ("h", "F")); produce 16?

This puzzles me.

Question 2. I have (seemingly successfully) done this:
my ($v1, $rest) = unpack ("C4 a*", $packet); my ($l, $payload) = unpack ("C2 a*, $rest);
If i  printf("%d\n", $l) i get 0.
However, exchanging the last line with
my ($l, $payload) = unpack ("H4 a*, $rest);
and print it, I get a 1, which seems correct from a protocol-perspective.

This puzzles me further.

How are these in-data strings actually converted? Am I correct in assuming that unpack simply formats data, regardless of input?

The final question is: Is it OK to use  my ($value) = unpack ("C4", $packet); and then treat $value as any number, i.e.  $field = ($value & 0x80000000) >> 24;?

If I instead do  my ($value) = unpack ("H8", $packet);, what am I in reality doing?

Solution and enlightenment

A colleague of mine figured it out, and I am humbled. Here is the cinch: H6 represents a string -- and it is perfectly fine to want a string of 3 bytes like that. However, C3 is not a string, it is 3 octets following each other, and to unpack it I shall have to use a list of 3 elements.

Today I have learned many things.

Replies are listed 'Best First'.
Re: Mysteries of unpack
by apl (Monsignor) on Jun 17, 2009 at 12:13 UTC
    why does this printf("%d\n", unpack ("h", "F")); produce '6' on my system?
    The unpack ("h", "F")); says 'Convert the letter capital-F into a hex-string, low byte first'. The hex for that letter is '46'. The low byte is '6'. You're printing an integer, and seeing it displayed.

      To get the desired result,

      >perl -e"printf(qq{%d\n}, unpack('C', pack('h', 'F')));" 15

      or

      >perl -le"print(hex('F'));" 15

      As you can see, the OP has pack and unpack backwards.

Re: Mysteries of unpack
by John M. Dlugosz (Monsignor) on Jun 17, 2009 at 16:23 UTC
    my ($value) = unpack ("C4", $packet); and then treat $value as any number, i.e. $field = ($value & 0x80000000) >> 24; ?
    I think you want to unpack a 4-byte integer there. So try N or V, not C ! I think you don't grasp what unpack is doing. You have 4 bytes in your packet, so you don't say "these are 4 bytes", you say what you want to produce from them. The length and encoding is implied by that. so, you say "interpret the next bytes as a 4-byte 2's complement integer in network byte order", or somesuch.