2

I have 65 different flags (options) for a custom data structure. Currently it looks like this:

struct CustomDataStruct {
    int Something;
    unsigned char Flags[9]
};

This way I'm able to store up to 72 flags (7 remaining, just in case I decide to add more). I want to use an individual bit for each flag, so I came up with this:

void SetFlag(struct CustomDataStructure* Struct, int FlagNr) {
    // Error checking and other stuff here
    int index = FlagNr / 8; array.
    Struct->Flags[index] |= 1 << (__________);

}

I've already tried with 1 << (FlagNr % 8) but it's not setting the correct bit. For example, I want to turn on flag ID 23 (starting from zero), so I call SetFlag(structInstance, 23), which correctly determines the index (Flags[2]), but 23 % 8 = 7, and 1 << 7 = 1000 0000 (in binary), instead of the correct value, which should be 0000 0001(turn on last bit of the 3rd uchar of the array, i.e bit no. 24).

Flags must be stored on this array, each bit representing the flag switch. Changing this is not an option.

Svtyros
  • 55
  • 8
  • 1
    Nitpick: I recommend against using `Struct` as an identifier in your actual code. Also avoid using the terms `Number` ("`Nr`") and `Index` to refer to the same thing as "Number" implies base 1 while "index" implies base 0. – Dai Jul 11 '19 at 04:57
  • If you're writing portable C, then I also recommend using an explicit `uint8_t` instead of `char` because there are non-octet platforms that C supports: https://stackoverflow.com/questions/2098149/what-platforms-have-something-other-than-8-bit-char – Dai Jul 11 '19 at 05:06
  • @Dai Thank you for these hints. This is just dummy code, in my actual project the flag mask is defined as `uint8_t Flags[9]`, and the identifiers are not the generic ones listed on my example, but more descriptive. – Svtyros Jul 11 '19 at 05:42

3 Answers3

3

Bits are typically indexed starting from the least significant (rightmost) bit, since in most contexts that makes more sense. If you want to reverse that, just do 1 << (7 - FlagNr % 8) or 0x80 >> (FlagNr % 8).

eesiraed
  • 4,626
  • 4
  • 16
  • 34
  • Works like a charm. So, for getting a flag status, would `bool getFlag(struct CustomDataStructure* Struct, int FlagNr) { return Struct->Flags[FlagNr/8] | 1 << (7 - FlagNr % 8) }` be correct? – Svtyros Jul 11 '19 at 17:36
  • @Svtyros Use `&` to check if a bit is set, not `|`. Otherwise, you're correct. – eesiraed Jul 11 '19 at 18:11
3

Rather than doing a bit shift, an array lookup works easily. FlagNr contains the zero based bit index so a value of 0 is the first bit in the first array element.

void setFlag( struct CustomDataStructure* thing, int FlagNr) {
    static uint8_t  masks[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
    size_t   index = FlagNr % 8;
    size_t   xndex = FlagNr / 8;
    thing->Flags[xndex] |= masks[index];
}
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
1
void setFlag( struct CustomDataStructure* foo, int flagIndex ) {

    assert( flagIndex >= 0 && flagIndex < 72 ); // Defensive programming!

    size_t arrayIndex = flagIndex / 8;
    int    bitShift   = flagIndex % 8;

    // If you want reverse (little-endian) bit order then subtract from 7:
    bitShift = 7 - bitShift;

    // This code is expanded for readability. An optimizing-compiler will still generate fast code:
    uint8_t flags = foo->Flags[ arrayIndex ];
    flags = flags | ( 1 << bitShift );
    foo->Flags[ arrayIndex ] = flags;
}
eesiraed
  • 4,626
  • 4
  • 16
  • 34
Dai
  • 141,631
  • 28
  • 261
  • 374