Adam S
Adam S

Reputation: 9245

Function accepting two arguments, a byte and a bit field, and returns the value of the field in the byte

I found some code online that performs this task:

byte = byte >> field;
byte = byte & 0x01;
return(byte);

However, I don't understand why we can't just do this:

return(byte & field);

Will this work? Why or why not? Are there better implementations?

Upvotes: 3

Views: 2585

Answers (6)

Swapnali
Swapnali

Reputation: 1

This can be given by a structure. Lets say:

struct POWERTRAIN_ERROR 
{

    uint8 ERROR_CODE;

    unit8 LAMP_STATUS : 1;
    };

    struct POWERTRAIN_ERROR   pt_error;

    uint8 func ( struct POWERTRAIN_ERROR pt)

    {

    // do something with pt.ERROR_CODE (which is a byte) and pt.LAMP_STATUS which is a bit field

    // lets say, this function needs to return the status of 0th bit of ERROR_CODE 

    return ( pt.ERROR_CODE & 0x1) ;

}

Upvotes: -1

phoxis
phoxis

Reputation: 61950

Shift byte to right

field represents the bit number of the word you have from the right hand side (LSB). byte = byte >> field will bring the bit number field of the byte byte at the LSB position. Then byte = byte & 0x01 ands the byte with 0x01 that means the result will contain a 1 in the LSB if it had the bit set in the bit number field originally, or will contain a 0 if it had the bit cleared at that position.

For example the test needed to check if the byte 0x52 has its bit number 4 set or not is shown below.

    byte   = 0x52 =  0 1 0 1 0 0 1 0

    field  = 0x04 =  0 0 0 0 0 1 0 0

    Operation: byte = byte >> field

    The bit number 4 is single quoted below. Note how it moves

                                  intermediate byte       | lost bits during
                                        states            | right shifting

    byte         = 0x52         = 0  1  0 '1' 0  0  1  0  |
    shift 1      = 0x29         = 0  0  1  0 '1' 0  0  1  | 0
    shift 2      = 0x14         = 0  0  0  1  0 '1' 0  0  | 1 0
    shift 3      = 0x0A         = 0  0  0  0  1  0 '1' 0  | 0 1 0
    shift 4      = 0x05         = 0  0  0  0  0  1  0 '1' | 0 0 1 0

    Note that the bit 4 is now moved at the LSB/righ most position of the byte
    now if we test the rightmost position of the above byte then we can check
    if the bit number 4 had its bit set or cleared, with the following operation

    Operation: byte = byte & 0x01

    byte is now 0x05

    byte         = 0x05  = 0 0 0 0 0 1 0 '1'
    AND                    & & & & & & &  &
                   0x01  = 0 0 0 0 0 0 0  1
                   ----    ----------------
                   0x01    0 0 0 0 0 0 0  1

   Now byte contains 0x01 so bit number 4 had the bit set. In the other case the
   final answer would be 0.

But we cannot do byte & field to check if the bit which is numbered field is set or cleared. This is because field is simply a binary and not a mask. If we did byte & field then the following would happen.

  byte         = 0x52  = 0 1 0 1 0 0 1 0
  AND                    & & & & & & & &
  field        = 0x04  = 0 0 0 0 0 1 0 0
                 ----    ---------------
                 0x00    0 0 0 0 0 0 0 0

The field has the value 0x04 which is, its bit number 2 set. With this operation we have checked actually if the bit number 2 is set. If the value of field was 5 then bit 0, and 2 would be set, so ANDing directly like above would result if extraction of the state of bit 0 and 2 in the value of byte, which can take four possible combination.

Shift 0x01 to left and make mask

Other ways to test the bit value of a byte is instead of shifting the byte itself, we shift the 0x01 mask field times to the left, and AND it with the byte, and check if is zero or not. (byte & (0x01 << field)) != 0 will be true when the field numbered bit is set or false otherwise.

   Operation: (0x01 << field)

      Shifting 0x01 to the left field times field = 0x04 for the example

                 = 0x01             = 0 0 0 0 0 0 0 1  
    shift 1      = 0x02             = 0 0 0 0 0 0 1 0
    shift 2      = 0x04             = 0 0 0 0 0 1 0 0
    shift 3      = 0x08             = 0 0 0 0 1 0 0 0
    shift 4      = 0x10             = 0 0 0 1 0 0 0 0


      After the left shift the '1' moves in the bit position 4
      Now we AND this with the byte to check if the bit position 4
      is set or clear.

  byte            = 0x52  = 0 1 0 1 0 0 1 0
  AND                       & & & & & & & &
  (0x01 << field) = 0x10  = 0 0 0 1 0 0 0 0
                    ----    ---------------
                    0x10    0 0 0 1 0 0 0 0

  Therefore the answer (0x01 != 0) is 1 there fore the bit 4 is set. It the bit 4
  was not set then the answer would be 0.

Use precomputed mask

If you have a byte with certain format which you need to test regularly, for example some bitfield of some pre defined word, where each bit means some specific thing then you can keep precomputer mask, which has a one only in the specific bit position which will be tested with that mask. For example to check for one byte the precomputer masks would be:

#define BIT_0 0x01 //(00000001)
#define BIT_1 0x02 //(00000010)
#define BIT_2 0x04 //(00000100)
#define BIT_3 0x08 //(00001000)
#define BIT_4 0x10 //(00010000)
#define BIT_5 0x20 //(00100000)
#define BIT_6 0x40 //(01000000)
#define BIT_7 0x80 //(10000000)

So to test the bit 4 in byte we have to do return (byte & BIT_4) or return (byte & BIT_4) != 0;

Depending on what the bit position represents the name of the macro could be set.

Upvotes: 1

Blagovest Buyukliev
Blagovest Buyukliev

Reputation: 43558

The first one is equivalent to:

return (byte >> field) & 0x01;

What it really does is shift to the bit with position field and return 1 if that bit is set, 0 otherwise.

The one you propose is incorrect because it doesn't shift to the offset of the designated field. For example, byte & 5 doesn't make any sense.

The function can as well be written like this:

return byte & (1 << field);

Of course, if you intend to pass 1 << 5 to it instead of 5, you can write it your way.

I suppose field is a number that indicates the position of the bit we are interested in, so for a single byte it would be in the range 0..7.

Upvotes: 3

Austin
Austin

Reputation: 51

The 1st example moves the required bit into the LSB of the return but the second example simply masks out all the bits that are not required.

Upvotes: 0

David Hammen
David Hammen

Reputation: 33126

If you really want the return value to be zero or one you can either

return ((byte & (1 << field)) != 0);

or

return ((byte >> field) & 0x01);

Both forms simplify a bit if all you care about is that the return value is zero or non-zero.

Upvotes: 1

Sven
Sven

Reputation: 22693

In the first code sample, field is the position of the bit in the field of which you want the value.

In the second sample, field would have to be an int with that bit set to one, i.e. 1 << field.

Upvotes: 1

Related Questions