2

I have a struct like the following:

struct Foo {
    unsigned int id;
    unsigned int flag_1 : 1;
    unsigned int flag_2 : 1;
    unsigned int flag_3 : 1;
    // Some arbitrary number of further flags. Code is
    // automatically generated and number will vary.
    // Notably, it may be more than an int's worth.
    int some_data;
    float some_more_data;
    // ...
};

From time to time, I need to reset all the flags to zero while preserving the rest of the struct. One way is obviously to set each flag to 0 individually, but it feels like there ought to be a way to do it in one fell swoop. Is that possible?

(Note that I am open to not using bit fields, but this is code that will sometimes run on memory-contrained systems, so the memory savings are very appealing.)

Edit:

There is a similar question here: Reset all bits in a c bitfield

However, the struct in that question is entirely bitfields. I cannot simply memset the entire struct to zero here, and the other answer involving unions is not guaranteed to work, especially if there are more than an int's worth of flags.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Dominick Pastore
  • 4,177
  • 2
  • 17
  • 29
  • Can't you use an array of unsigned int for flags? You can iterate over flags – Abhay Aravinda Mar 31 '20 at 17:06
  • https://stackoverflow.com/questions/27121427/reset-all-bits-in-a-c-bitfield – yano Mar 31 '20 at 17:08
  • Does this answer your question? [Reset all bits in a c bitfield](https://stackoverflow.com/questions/27121427/reset-all-bits-in-a-c-bitfield) – sabbahillel Mar 31 '20 at 17:30
  • @AbhayAravinda That is a valid option, but I'd like to avoid it if possible for the memory savings. – Dominick Pastore Mar 31 '20 at 17:31
  • @yano I did see that question, but the struct there is entirely bitfields. I can't just clear the whole struct in this case, and the answer involving unions seems unsafe. – Dominick Pastore Mar 31 '20 at 17:33
  • Why are you using int for flags? won't char occupy lesser bytes? – Abhay Aravinda Mar 31 '20 at 17:34
  • 1
    @AbhayAravinda `unsigned int` in this case is not referring to the actual size in memory, just how the value is interpreted. (I'm not 100% sure if it affects alignment boundaries.) The `:1` determines how many bits are actually used. See [this bit field primer](https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm). – Dominick Pastore Mar 31 '20 at 17:46

2 Answers2

7

Just use a separate struct for the flags:

struct Foo_flags {
    unsigned int flag_1 : 1;
    unsigned int flag_2 : 1;
    unsigned int flag_3 : 1;
    // ...
};

struct Foo {
    unsigned int id;
    struct Foo_flags flags;
    int some_data;
    float some_more_data;
    // ...
};

Or even a simpler nested struct:

struct Foo {
    unsigned int id;

    struct {
        unsigned int flag_1 : 1;
        unsigned int flag_2 : 1;
        unsigned int flag_3 : 1;
        // ...
    } flags;

    int some_data;
    float some_more_data;
    // ...
};

Then, later in your code:

struct Foo x;
// ...
x.flags.flag_1 = 1;
// ...
memset(&x.flags, 0, sizeof(x.flags));
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
4

With some minor adjustments, you can use the offsetof macro to find the beginning and end of the "flag" data within the structure, then use memset to clear the relevant memory. (Note that you cannot use offsetof directly on bitfields, hence the addition of the flag_beg member!)

Here's a working example:

#include <stdio.h>
#include <stddef.h>  // defines offsetof
#include <string.h>  // declares memset

struct Foo {
    unsigned int id;
    unsigned int flag_beg;    // Could be unsigned char to save space
    unsigned int flag_1 : 1;
    unsigned int flag_2 : 1;
    unsigned int flag_3 : 1;
    unsigned int flag_end;    // Could be unsigned char to save space
    // Some arbitrary number of further flags. Code is
    // automatically generated and number will vary.
    // Notably, it may be more than an int's worth.
    int some_data;
    float some_more_data;
    // ...
};

#define FBEG (offsetof(struct Foo, flag_beg))
#define FEND (offsetof(struct Foo, flag_end))

int main()
{
    struct Foo f;
    f.id = 3; f.flag_1 = 1; f.flag_2 = 0; f.flag_3 = 1;
    f.some_data = 33; f.some_more_data = 16.2f;

    printf("%u %u %u %u %d %f\n", f.id, f.flag_1, f.flag_2, f.flag_3, f.some_data, f.some_more_data);
    memset((char*)(&f) + FBEG, 0, FEND - FBEG);
    printf("%u %u %u %u %d %f\n", f.id, f.flag_1, f.flag_2, f.flag_3, f.some_data, f.some_more_data);
    return 0;
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83