简体   繁体   中英

What is the best way to initialize a bitfield struct in C++?

In C++, I have a class which contains an anonymous bitfield struct. I want to initialize it to zero without having to manually write out all fields.

I can imagine putting the initialization in three places:

  1. Create a constructor in the bitfield
  2. Zero out in the initializer list of the constructor for the containing class
  3. Zero out in the body of the constructor for the containing class

This bitfield has many fields, and I'd rather not list them all.

For example see the following code:

class Big {
    public:
        Big();

        // Bitfield struct
        struct bflag_struct {
            unsigned int field1 : 1;
            unsigned int field2 : 2;
            unsigned int field3 : 1;
            // ...
            unsigned int field20 : 1;
            // bflag_struct(); <--- Here?
        } bflag;

        unsigned int integer_member;
        Big         *pointer_member;
}

Big::Big()
  : bflag(),             // <--- Can I zero bflag here?
    integer_member(0),
    pointer_member(NULL)
{
    // Or here?
}

Is one of these preferable? Or is there something else I'm missing?

Edit: Based on the accepted answer below (by Ferruccio) I settled on this solution:

class Big {
    // ...

    struct bflag_struct {
        unsigned int field 1 : 1;
        // ...
        bflag_struct() { memset(this, 0, sizeof *this); };
    }

    // ...
}

You could always do this in your constructor:

memset(&bflag, 0, sizeof bflag);

Union the bitfield struct with something easier to initialize to 0.

You could use a union, although that would add an extra level of indirection when accessing the fields:

class Big {
    union {
        struct {
            unsigned int field1 : 1;
            ...
        } fields;
        unsigned int all_fields;
    };
    ...
};

Big::Big()
  : all_fields(0),
    ...
{
    ...
}

MSVC allows anonymous structs inside of unions (see, eg the definition of D3DMATRIX in <d3d9.h> ), but this is a non-standard C++ extension which you should avoid using if you can.

As an aside, unless you need the bitfield to interface to some legacy code, you shouldn't use them. They are are inherently unportable and inefficient.

Your use of a function-like initializer (marked "Can I zero bflag here?") is 100% sufficient to initialize your POD struct with 0 values.

Unless you know your compiler is broken in this regard, doing any additional initialization of those members is initializing it twice for no benefit.

EDIT: Just for 'fun' I just checked this with VS2005, VS2008, GCC 3.4.4, GCC 4.2, and Borland C++ 5.5.1... only Borland C++ 5.5.1 gets it wrong.

And I say 'wrong' because it seems to me that 8.5 and 8.5.1 of the standard imply that the function-like initializer should zero-init the POD struct.

BTW C++20 supports initializing the bitfields in the class definition eg

class ... {
   int foo : 1 {};
}

gcc with -std=c++2a to enable

you could Zero the memory using ZeroMemory or memset in the constructor that way it look's cleaner.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM