2

Let's say I have a C structure defined as

struct data {
    /* some memebers */

    int flag_a:1;
    int flag_b:1;
    int flag_c:1;

    /* some other members */
}

Is there a way to take advantage of the bitfields being represented as a single int in memory and write the condition s.flag_a | s.flag_b | s.flag_c as a simpler expression such as s.flags?

Or would a smart compiler such as GCC be able to actually deduce it?

Edit: To make myself absolutely clear: I'm looking for a portable way to test for all the flags being set without explicitly testing each of the flags separately.

David
  • 1,055
  • 8
  • 23
  • 1
    Are you looking for `union`? – Eugene Sh. Nov 01 '16 at 14:24
  • I don't think so, I would like to make the test of any flag being set being as fast as possible. – David Nov 01 '16 at 14:25
  • 2
    I **do** think you are looking for `union`... Union this bitfield with an `int` field and compare that `int` with zero. Voila. – Eugene Sh. Nov 01 '16 at 14:27
  • I'm not sure I understand the question, but if all bits are represented in the same variable, then you could create a mask and make an "OR" operation ` int a = 5; // corresponds to.....101 // last three bits are flags a, b and c. int mask = 0; // all bits are 0 int res = a | mask; // if res >0, then at least one bit is up! ` – PhoenixBlue Nov 01 '16 at 14:29
  • @EugeneSh. *Union this bitfield with an `int` field and compare that `int` with zero. Voila.* That's non-portable. – Andrew Henle Nov 01 '16 at 14:38
  • @AndrewHenle Relying on reinterpretation of unions and bitfields is not portable generally. But I can't think of *any* architecture having some bits in `int` set, but the whole `int` to be equal zero. – Eugene Sh. Nov 01 '16 at 14:41
  • @EugeneSh.: Unused bits in that `int` will have indeterminate value. There is no guarantee that `int` will compare zero! – too honest for this site Nov 01 '16 at 14:55
  • @EugeneSh. There is no guarantee that the bits are even allocated in the same `int`. The compiler is free to do something stupid like tossing in 31 bits of padding after the first data bit. – Lundin Nov 01 '16 at 15:04
  • Why the downvote? – David Nov 01 '16 at 16:01
  • @Lundin: If I read the standard correctly, the implemenation very well has to pack the bits into the same `int` unit. – too honest for this site Nov 02 '16 at 19:21
  • @EugeneSh.: Consider an 8 bit CPU which only accesses the byte with the three bits for set/clear/etc. If you compare via type-punning to a full-size `int`, it will read the indeterminate byte, too. Alternatively it could have one bit in the 2nd byte and exploit the fact its other bits are don't care for optimisation. – too honest for this site Nov 02 '16 at 19:23

2 Answers2

7

This isn't possible to do portably, in any deterministic way. The problem is that the C standard does not guarantee anything about those bits: you can't know which bit that is the LSB nor can you know if there is padding. On top of that, endianess is also an issue. (And in theory, different signedness formats.) See this for details.

In theory you could create a union between this bit field and one with : 3 bits, but the result of such practice will not be predictable nor well-defined.

The best solution is to get rid of the bit-field and replace it with a deterministic, 100% portable solution:

typedef struct
{
  uint8_t flags;
} data_t

#define FLAG_A 0x01u
#define FLAG_B 0x02u
#define FLAG_C 0x04u
#define FLAG_ALL (FLAG_A | FLAG_B | FLAG_C)

data_t data = { .flags = FLAG_A | FLAG_B | FLAG_C};

if(data.flags & FLAG_ALL)
  ...
Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
2

Bit field use is entirely non-portable. You can't be sure where each field is in the underlying structure. Per 6.7.2.1 Structure and union specifiers, paragraph 11 of the C Standard:

An implementation may allocate any addressable storage unit large enough to hold a bitfield. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • That does not answer the question. OP does not care where in the `int` the fields are. – too honest for this site Nov 02 '16 at 13:48
  • @Olaf *That does not answer the question. OP does not care where in the `int` the fields are* You just implicitly assumed that the bit fields are in actually the same `int` - an unsafe assumption. If you can't even safely assume they're in the same `int`, you can't rely on the mapping within that `int`. What the OP was proposing is *entirely* implementation-defined and non-portable, to the point of a different compiler on the exact same architecture producing different results. Please don't downvote when you don't understand. – Andrew Henle Nov 02 '16 at 17:11
  • 1
    "You just implicitly assumed that the bit fields are in actually the same" - I don't. OP asks if there is a way to test all bits at once; he just does not care if and where they are located. However, the standard very well requires the bits for this specific `struct` **are** in the same `int`: "If enough space remains, a bit-field that immediately follows another bit-field in a structure **shall be packed** into adjacent bits of the **same** unit". `int` has at least 16 bits, so for 3 bits it is guaranteed they fit into the same `int`. That is not the problem, but the other 13+ bits. – too honest for this site Nov 02 '16 at 19:09