Phlucious
Phlucious

Reputation: 3843

How are single-bit (boolean) members in bit fields handled?

When I request or set a single-bit member of a bit-wise struct/class, does the compiler do a bit shift? For example, given this struct:

struct {
    unsigned char thing : 4;
    unsigned char flag1 : 1;
    unsigned char flag2 : 1;
    unsigned char reserved : 2;
}

...does the compiler realize that bit-shifting isn't required? In other words, does the compiler do this:

uchar request_flag1() const {
    uchar temp = data & 0x40;       //0100 0000 - get the 7th bit
    return temp >> 7;               //0000 0001 - return the shifted value
}
void set_flag1(uchar v) {
    data &= 0x191;                  //1011 1111 - clear the 7th bit
    data |= v << 7;                 //0v00 0000 - set the 7th bit to shifted value
}

or this?

bool request_flag1() const {
    return data & 0x40;             //0100 0000 - simply check whether the 7th bit is set
}
void set_flag1(bool v) {
    if(v) data |= 0x40;             //0100 0000 - simply set the 7th bit
    else data &= 0x191;             //1011 1111 - simply clear the 7th bit
}

I imagine that the latter would be significantly faster since it's half the number of operations.

If the latter is true, would I have to declare the bit field members as type bool to get this advantage?

Upvotes: 0

Views: 146

Answers (2)

Klaus
Klaus

Reputation: 25663

Your question can not be answered in general. Every compiler is free to decide how a bitfield is implemented. There is no guarantee that it is high bit first or low bit first. This can depend on system endieness but also that is no guarantee. So using a union conversion for bit-field is definitely not portable!

The code the compiler can generate depends on the compiler and the cpu it has to create code for. If you want to test and set a bit for example, some cpu architectures support a single opcode/instruction exactly for that usage. An other cpu may be only able to check the lsb so it must shift it n times to catch the bit you want. Some other cpu may work with a and/or combination.

Simple answer: It depends :-)

But there is nearly a guarantee that a modern compiler will do its best to generate the smallest or fasted code which can do the job on the selected cpu.

If you really want to know what your compiler generates, simply look in the generated assembly.

on linux you can use: objdump -S a.out this gives you the assembly and the source code intermixed.

Upvotes: 0

Marc B
Marc B

Reputation: 360872

The compiler will convert your bit operation into whatever series of bitwise-and/or/not operations are necessary to accomplish the job.

e.g.

s.flag1 = 1;

would become

s = s | 00000010;
        ^^^^^^-----stuff
              ^----flag1
               ^---flag2

and the actual value assigned would depend on the bit/byte ordering of the particular CPU you're compiling for.

Upvotes: 2

Related Questions