in reply to Pack/unpack irregularity

Updated node - original 'answer' replaced with explaination.

I originally thought you could get away with using "h*" instead of "H*", but jsprat is correct - it is the "%2x" that matters. So, why?

When you format the number 1 with "%1x" and pack it, you get the hexidecimal number 10 (binary number '00010000') when you format it with "%2x" and pack it, you get the hexidecimal number 1 (binary number '00000001'):

        %1x         %2x
1    0001 0000   0000 0001
2    0010 0000   0000 0010
3    0011 0000   0000 0011
So, 1 becomes hex 10, 2 becomes hex 20, 3 becomes hex 30, and so on. Once we hit 16, however, we get the results we expect. The problem lies in the formatted 'string' we are packing. When you format the number with "%2x", you get a leading space added for any decimal number less than 16, AKA hexidecimal numbers that only use 1 digit:
     %1x  %2x
1    '1'  ' 1'
2    '2'  ' 2'
Now, try these one-liners:
perl -le 'print unpack("H*",pack("H*",1))' perl -le 'print unpack("H*",pack("H*"," 1"))' perl -le 'print unpack("H*",pack("H*","01"))'
See the difference? I believe that unpack is expecting at least two digits, so it adds a zero for you - in the wrong place. The moral is to pad your hex numbers with a leading 0 if they are less then 2 digits.

Now, there is more than one way to skin this cat. Don't be tempted to think that pack is the only culprit - unpack will throw a monkey wrench in the system as well. For example, consider this one-liner that works for one-digit hex numbers:

perl -le 'print unpack("h*",pack("H*","1"))'
Are we having fun yet? ;)

Also note that you will need to use more than two nibbles for values over 255. Formatting with "%4x" will handle up to 65535, AKA (2^16) - 1.

jeffa

L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)

Replies are listed 'Best First'.
Re: (jeffa) Re: Pack/unpack irregularity
by greenFox (Vicar) on May 30, 2002 at 23:51 UTC
    Just noting that the original poster used "%lx" (lower case "l") not "%1x" (number one)... your explanation is still good though - sprintf would have to default to 1 - defaulting to 0 would be bad! :)

    --
    my $chainsaw = 'Perl';