in reply to Extracting Bit Fields (Again)

There are no rotate readily available in Perl, but Perl does have shift operators (<< and >>) and that's all you need:

$D1 = ($num >> 7) & 0x01; # 1 bit starting at bit 7. $D2 = ($num >> 4) & 0x07; # 3 bits starting at bit 4. $D3 = ($num >> 0) & 0x0F; # 4 bits starting at bit 0.

The above is much easier than using unpack because unpack('b', ...) returns a string representation of the number. You can work around it as follows (for fields no bigger than 8 bits):

@D = map { unpack('C', pack('b*', $_)) } unpack('b1b3b4', 162);

Replies are listed 'Best First'.
Re^2: Extracting Bit Fields (Again)
by Aristotle (Chancellor) on Oct 12, 2005 at 05:27 UTC

    This is the approach I’d take, as well.

    Now if you go one step further, you can reorder and rewrite this like so:

    $D3 = ( $num >> 0 ) & ( 1 << 4 ) - 1; # 4 bits starting at bit 0 $D2 = ( $num >> 4 ) & ( 1 << 3 ) - 1; # 3 bits starting at bit 4 $D1 = ( $num >> 7 ) & ( 1 << 1 ) - 1; # 1 bit starting at bit 7

    And then destructively rewrite the input:

    $D3 = $num & ( 1 << 4 ) - 1; # 4 bits starting at bit 0 $num = $num >> 4; $D2 = $num & ( 1 << 3 ) - 1; # 3 bits starting at bit 4 $num = $num >> 3; $D1 = $num & ( 1 << 1 ) - 1; # 1 bit starting at bit 7 $num = $num >> 1;

    Hmm…

    @width = ( 4, 3, 1 ); $D3 = $num & ( 1 << $width[ 0 ] ) - 1; # 4 bits starting at bit 0 $num = $num >> $width[0]; $D2 = $num & ( 1 << $width[ 1 ] ) - 1; # 3 bits starting at bit 4 $num = $num >> $width[ 1 ]; $D1 = $num & ( 1 << $width[ 2 ] ) - 1; # 1 bit starting at bit 7 $num = $num >> $width[ 2 ];

    So obviously:

    sub bitfield { my ( $num, @field ) = @_; my @value; for my $width ( @field ) { push @value, $num & ( 1 << $width ) - 1; $num = $num >> $width; } return @value; }

    Unfortunately, this works only for bitfields up to the architecture integer size. It is possible with some contortions to cut fields from a string longer than 32 or 64 bits if you pluck the right pieces out manually, but no individual bitfield can ever be longer than 32/64 bits.

    Makeshifts last the longest.

Re^2: Extracting Bit Fields (Again)
by ozboomer (Friar) on Oct 12, 2005 at 05:29 UTC
    There is a rotate... I'd just forgotten about it... and this way is the simplest and clearest for what I need to do:-
    $D1 = ($intbuf & 0x80) ? 1 : 0; $D2 = ($intbuf >> 4) & 0x07; $D3 = ($intbuf & 0x0F);
    My fogged brain can now keep struggling away at this job...

    Many, many thanks for all your help, folks.

      There is a rotate...
      huh? no Or are you talking about some module?
        Sorry about that... my slack use of the language(!)

        I mean a 'right shift operator' (the '>>'). Sometimes I revert to assembler or C -style constructs/language and I use the terms interchangably... but it's really just 'rotating the bits (right)' that I was trying to remember.