Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is this a correct way to initialize all the bit fields in a struct?

I’m packing bools together in a c++ struct and I want to initialize them all to zero when constructed.

Is this a correct/safe way to do it?

I think it is but I’m not 100% sure and I’d like the lawyers to weigh in…

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

struct packed_flags {
  // All the flags (there's less than 16 of them)
  bool f1: 1;
  bool f2: 1;
  bool f3: 1;
  bool f4: 1;
  // ...

  // Pad the struct to a 16-bit size
  uint16_t: 0;

  // Constructor to initialize them all to 'false'
  packed_flags() {
    *(uint16_t*)(this) = 0;
  }
} flags;

>Solution :

*(uint16_t*)(this) = 0; is an aliasing violation and therefore undefined behavior. *this is not of type uint16_t nor does any object of type uint16_t exist that is pointer-interconvertible with *this.

The correct way to force the default constructor to zero all members is to not write any default constructor at all, instead relying on the implicitly-defined one, and explicitly specifying default member initializers instead (since C++20):

struct packed_flags {
  // All the flags (there's less than 16 of them)
  bool f1: 1 = 0;
  bool f2: 1 = 0;
  bool f3: 1 = 0;
  bool f4: 1 = 0;
  // ...

  // Pad the struct to a 16-bit size
  uint16_t: 0 = 0;
} flags;

Before C++20 you can simply write a default constructor that assigns 0 to each bit-field manually.

Or, even without these default initializers you can use initialization by () or {}, to force zero-initialization (since C++03/C++11):

struct packed_flags {
  // All the flags (there's less than 16 of them)
  bool f1: 1;
  bool f2: 1;
  bool f3: 1;
  bool f4: 1;
  // ...

  // Pad the struct to a 16-bit size
  uint16_t: 0;
} flags = {};

Also, uint16_t: 0; is not guaranteed to pad the structure as you want it. It only specifies that the next bit-field shall begin at a new bit-field allocation unit boundary, but there is no following bit-field.

If you want to force the structure to have a specific alignment (implying that its size is an integer multiple of that alignment), then you should use alignas instead:

struct alignas(2) packed_flags {
  // All the flags (there's less than 16 of them)
  bool f1: 1;
  bool f2: 1;
  bool f3: 1;
  bool f4: 1;
  // ...
} flags = {};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading