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

Oh great and wise ones I pray for enlightenment. I shall let the code speak first.

#!/usr/bin/perl use warnings; use strict; for(0..32) { my $number = int rand(16**6); my $packed_away = pack "I*" , $number; my @unpacks; push @unpacks, unpack "B32", $packed +_away; push @unpacks, join " ", unpack "B16 B16", $packed +_away; push @unpacks, join " ", unpack "B8 B8 B8 B8", $packed +_away; push @unpacks, join " ", unpack "B4 B4 B4 B4 B4 B4 B4 B4", $packed +_away; printf "%-8i %s\n", $number, (join " ", @unpacks); } __END__ 11689403 00000000101100100101110110111011 0000000010110010 01011101101 +11011 00000000 10110010 01011101 10111011 0000 1011 0101 1011 8041308 00000000011110101011001101011100 0000000001111010 10110011010 +11100 00000000 01111010 10110011 01011100 0000 0111 1011 0101 5462194 00000000010100110101100010110010 0000000001010011 01011000101 +10010 00000000 01010011 01011000 10110010 0000 0101 0101 1011 1901913 00000000000111010000010101011001 0000000000011101 00000101010 +11001 00000000 00011101 00000101 01011001 0000 0001 0000 0101 10562565 00000000101000010010110000000101 0000000010100001 00101100000 +00101 00000000 10100001 00101100 00000101 0000 1010 0010 0000 4113795 00000000001111101100010110000011 0000000000111110 11000101100 +00011 00000000 00111110 11000101 10000011 0000 0011 1100 1000 11898830 00000000101101011000111111001110 0000000010110101 10001111110 +01110 00000000 10110101 10001111 11001110 0000 1011 1000 1100 5570479 00000000010101001111111110101111 0000000001010100 11111111101 +01111 00000000 01010100 11111111 10101111 0000 0101 1111 1010

Sorry for the ugly output, it does not line wrap on my tty here.

Why do I get 32 bits of binary for all the unpacks except the last one (eight times 4 bits) ? The last one is of course the one I want for the script I am playing with :(

Cheers,
R.

Pereant, qui ante nos nostra dixerunt!

Replies are listed 'Best First'.
Re: binary pack/unpack oddness
by BrowserUk (Patriarch) on Jan 24, 2005 at 18:36 UTC

    The minimum chunk of memory processed by any single unpack pattern element is a byte. Hence, when you unpack a 32-bit element using repeated B4 elements, you get a value that represents the high 4-bits of each byte and the low 4-bits ar discarded. This may be made clearer by:

    $b = pack 'I*', 0x12345678; print join'|', unpack '(B4)*', $b; 0111|0101|0011|0001

    As you can see the (four!) values returned by unpack are the high 4-bits from each of the 4 bytes (in reverse order).

    What I think you are after can be done like this:

    $b = pack 'I*', 0x12345678; print join'|', unpack '(A4)*', unpack 'B*', $b; 0111|1000|0101|0110|0011|0100|0001|0010

    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.

      Ah Ha! that's the problem.

      I had the internal assumption that unpack would just take as many bits as it needed and keep the rest for the next unpack. Your solution is also perfect.

      Many Thanks,
      R.

      Pereant, qui ante nos nostra dixerunt!