in reply to Extracting Bit Fields (Again)

If you aren't using a very old perl, this should do it (update: slight tweaks):
my ($d1, $d2, $d3) = map oct "0b$_", sprintf("%08b", 162) =~ /(.)(...) +(....)$/;
I'd appreciate it if someone could explain just what unpack "b1b3b4", 162 actually does; I've never found the pack documentation to be particularly informative.

Replies are listed 'Best First'.
Re^2: Extracting Bit Fields (Again)
by BrowserUk (Patriarch) on Oct 12, 2005 at 09:32 UTC

    Not quite what people above think it does.

    perl> printf "%b\n", 162;; 10100010 perl> print unpack 'b1b3b4', 162;; 1 011 0100 perl> print unpack 'B1B3B4', 162;; ## In case of different endian mach +ines. 0 001 0011

    Update: The 'Bn' and 'bn' formats unpack bits from bytes, starting from least or most significant bits, but each 'Bn' unpack bits from a whole number of bytes. And always starting at a byte boundary.

    So 'b1b3b4' unpacks 1, 3, & 4 bits from each of 3 different bytes. Even if there are more bits in the current byte, and new byte is started when the next Bn is processed.

    Vis:

    perl> print unpack '(B8)4', pack 'N', 0b11111111_10101010_01010101_000 +00000;; 11111111 10101010 01010101 00000000 perl> print unpack '(B4)4', pack 'N', 0b11111111_10101010_01010101_000 +00000;; 1111 1010 0101 0000

    And if n>8, then more than one byte are used for the 'bn', but a new byte is started for the next format.

    perl> print unpack '(B16)2', pack 'N', 0b11111111_10101010_01010101_00 +000000;; 1111111110101010 0101010100000000 perl> print unpack '(B12)2', pack 'N', 0b11111111_10101010_01010101_00 +000000;; 111111111010 010101010000

    But the significant thing here is that I have packed the input to a binary value.

    With pack 'b1b3b4', 162 quite where the input is drawn from is a mystery. the 162 obviously has a binary representation within the scalar, but this would be in the SvIV, and if it were that being decoded you would get this result:

    perl> print unpack '(b8)3', pack 'V', 162;; 01000101 00000000 00000000 perl> print unpack 'b1 b3 b4', pack 'V', 162;; 0 000 0000

    Ie. The first 1, 3, & 4 bits of the first 3 bytes of the 4-byte binary rep of 162--but you don't.

    You get this:

    perl> print unpack '(B8)3', 162;; 00110001 00110110 00110010 perl> print unpack 'B1B3B4', 162;; 0 001 0011

    which shows where the 1, 011 & 01 come from. The first 1, 3 & 4 bits of three consecutive bytes, but that still leaves the question of where those bytes come from?

    And the answer appears to be from the ascii values for 1, 6 & 2. And my guess is that as the scalar into which the bareword 162 is placed has never been used in a numeric context, so it is the string representation that is being unpacked. Hence this gives the same result:

    perl> print unpack 'B1B3B4', '162';; 0 001 0011

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
      Thanks; I had suspected it was using the string "162", but it didn't occur to me it might be applying each B/b to a new byte.