Bit field structures and C++

M

Marcel Müller

Hi,

is the following code valid?

#include <stdio.h>

struct X
{ bool f1:1;
bool f2:1;
};

int main(int argc, char* argv[])
{ X x;
x.f1 = true;
x.f2 = false;
printf("%u %u %u\n", x.f1, x.f2, sizeof x);
return 0;
}

While all my compiler seem to eat the combination of bool and bit
fields, it is not that straight forward, because normally it must be an
unsigned integer type. And there is no implicit conversion from that to
bool.

In fact, the compilers also translate the following structure without
warning:

struct X
{ bool f1:2;
bool f2:2;
};


If the code at the top is valid I would like to prefer this over
enumeration types with the usual power of two values.

Unfortunately at least gcc seems not to optimize expressions like
if (x.f2)
in a way to avoid the logical shift.


Marcel
 
E

Erik Wikström

Hi,

is the following code valid?

#include <stdio.h>

struct X
{ bool f1:1;
bool f2:1;
};

int main(int argc, char* argv[])
{ X x;
x.f1 = true;
x.f2 = false;
printf("%u %u %u\n", x.f1, x.f2, sizeof x);
return 0;
}

While all my compiler seem to eat the combination of bool and bit
fields, it is not that straight forward, because normally it must be an
unsigned integer type. And there is no implicit conversion from that to
bool.

C++ allows bool bitfields.
In fact, the compilers also translate the following structure without
warning:

struct X
{ bool f1:2;
bool f2:2;
};


If the code at the top is valid I would like to prefer this over
enumeration types with the usual power of two values.

Unfortunately at least gcc seems not to optimize expressions like
if (x.f2)
in a way to avoid the logical shift.

I doubt that there is any way to implement a bitfield without the shift,
and often also masking.
 
M

Marcel Müller

Erik said:
C++ allows bool bitfields.

OK, thanks.

I doubt that there is any way to implement a bitfield without the shift,
and often also masking.

In the above case: yes.

If I had implemented the same semantic by an enumeration type, the
condition above would look like
enum Y
{ f1 = 1,
f2 = 2,
};
Y y;
if (y & Y::f2)
or similar. This does not require a shift operation, of course. In the
same way a compiler could optimize the condition
if (x.f2)
by using a mask and a comparsion to zero.
Btw. gcc really does more complex optimizations. E.g. the initial code
int main(int argc, char* argv[])
{ X x;
x.f1 = true;
x.f2 = false;
printf("%u %u %u\n", x.f1, x.f2, sizeof x);
return 0;
}

is in fact translated as
int main(int argc, char* argv[])
{ X x;
x.f1 = true;
x.f2 = false;
printf("%u %u %u\n", 1, 0, 1);
return 0;
}
So gcc realized that x.f1 and x.f2 are in fact constant at the execution
of printf. The same applies to 'if' unless I put it into a subfunction
with an X& argument.


Marcel
 
J

James Kanze

is the following code valid?
   #include <stdio.h>
   struct X
   {
bool f1:1;
     bool f2:1;
   };
   int main(int argc, char* argv[])
   {
X x;
     x.f1 = true;
     x.f2 = false;
     printf("%u %u %u\n", x.f1, x.f2, sizeof x);
     return 0;
   }
While all my compiler seem to eat the combination of bool and
bit fields, it is not that straight forward, because normally
it must be an unsigned integer type. And there is no implicit
conversion from that to bool.

No implicit conversion of what to bool? In this case, you're
passing a type bool as a vararg. In C++, bool is an integral
type, so integral promotions apply---the actual argument will be
passed as an int with value of either 0 or 1. In C (and I'm
pretty sure in C++ as well), int's and unsigned int's with the
same values have the same representation, and this special case
of type mismatch is legal. (Note that if you passed a negative
value, it would be undefined behavior.)

Of course, in this particular case, C++ offers better
alternatives:
std::cout << x.f1 << ' ' << x.f2 ...
In fact, the compilers also translate the following structure
without warning:
   struct X
   {
bool f1:2;
     bool f2:2;
   };

Why shouldn't it?
If the code at the top is valid I would like to prefer this
over enumeration types with the usual power of two values.

But they don't do the same thing.
Unfortunately at least gcc seems not to optimize expressions
like
   if (x.f2)
in a way to avoid the logical shift.

That sounds like a problem with the optimizer. I'd ask about it
in a g++ newsgroup, or even post it as a bug report (or an
enhancement request).
 
J

James Kanze

Hi,
is the following code valid?
#include <stdio.h>
struct X
{ bool f1:1;
bool f2:1;
};
int main(int argc, char* argv[])
{ X x;
x.f1 = true;
x.f2 = false;
printf("%u %u %u\n", x.f1, x.f2, sizeof x);

BTW, you're passing a size_t where printf() expects an
unsigned int. On machines where size_t is a larger type, like
unsigned long, this will yield undefined behavior.

Formally, it has nothing to do with the size of size_t per se.
size_t is a typedef; if it is defined to be unsigned long, you
have undefined behavior, even if the sizes are the same.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top