Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: Extracting Bit Fields (Again)

by BrowserUk (Patriarch)
on Oct 12, 2005 at 04:26 UTC ( [id://499368]=note: print w/replies, xml ) Need Help??


in reply to Extracting Bit Fields (Again)

Here is one way to do it (but you aren't going to like it!):

print unpack 'C*', pack '(B8)*', map{ substr '00000000'.$_, -8 } unpack 'A1A3A4',unpack 'B*',pack 'C', 162;; 1 2 2

To explain that, (right-to-left):

## pack 162 into an 8-bit binary value (a char). pack 'C', 162 ## unpack that into it's bits, (asciized binary bitstring). unpack 'B*', ## split that into the 3 fields. ('1','010', '0010' ). unpack 'A1A3A4', ## Pad each to the smallest size (8 bits) that Perl can deal with nume +rically. map{ substr '00000000'.$_, -8 } ## Pack them back up to binary values (chars). pack '(B8)*', ## And unpack them back to numeric values. unpack 'C*', ## and convert those to ascii-decimal for display print

The problem with vec is that it only allows you to deal with bits in quantites that are powers of 2, and on powers of two boundaries, which makes dealing with your 3-bit field problematic.

Probably easier to use is a subroutine like this:

#! perl -slw use strict; sub bitField { my( $value, $offset, $size ) = @_; my $mask = ( ( 1<<$size) - 1 ) << $offset; return ( $value & $mask ) >> $offset; } print bitField 162, 7, 1; print bitField 162, 4, 3; print bitField 162, 0, 4; __END__ P:\test>499354 1 2 2

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.

Replies are listed 'Best First'.
Re^2: Extracting Bit Fields (Again)
by oyster2011 (Initiate) on Dec 22, 2011 at 05:23 UTC
    I really liked this code snippet and the detailed explanation that you have provided. I have a requirement to parse a 32-bit register with bit fields and produce a human readable values for each field. For example, I have a register definition like: LinkStatus: 2 # 2 bits for this field CardStatus: 3 Reserved: 7 IntrStatus: 15 etc..etc Given a hex value, I would like to output something like: LinkStatus = 3 CardStatus = 0 Reserved = 0 IntrStatus = 200 etc... I tried to use the above method, but I guess the field sizes are in 8 bits.. Wondering if we can use pack/unpack for this or should I use the more classical bit extraction operators (<< and >> )? Appreciate pointers on this. Thanks.

      Maybe something like this would work for you? (Update: simplified code):

      Update 2: Unsimplified code to correct errors noted by oyster2011 below (Thanks!):

      #! perl -slw use strict; sub bitFields{ my( $val, $pat ) = @_; my @fields = unpack $pat, reverse unpack 'b32', pack 'L', $val; return unpack 'L*', pack '(b32)*', map scalar( reverse), @fields; } my( $linkStatus, $cardStatus, $reserved, $intrStatus ) = bitFields( 123456789, 'x2 a2 a3 a7 a15' ); print for $linkStatus, $cardStatus, $reserved, $intrStatus; __END__ C:\test>bitFields.pl 0 3 86 31138

      Use 'xn' in the template to skip over bits you aren't interested in. You might need to use 'B32' instead of 'b32' depending upon your platform.

      Masking and shifting is almost certainly quicker, but this could be seen as a nice abstraction.

      You could also do away with the intermediates if that floats your boat:

      sub bitFields{ unpack 'L*', pack'(b32)*', map scalar( reverse), unpack $_[1], reverse unpack 'b32', pack 'L', $_[0]; }

      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      The start of some sanity?

        Thank you so much for the quick response. I was trying to understand the code output.

        But here is what I find: Input is : 123456789 (decimal) = 0x075BCD15 (hex, little endian) = 0000_0111_0101_1011_1100_1101_0001_0101 (binary)

        So, if we use the template 'x2 a2 a3 a7 a15', we should have 00 for x2 00 for a2 011 for a3 1010110 for a7 111100110100010 for a15 The output in hex should be 0 0 3 56 79A2 Is this right? I seem to be missing something here.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://499368]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (2)
As of 2024-04-26 05:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found