Bitfields in struct

J

Jason Curl

Hello C Group,

From what I remember, it is implementation dependent the way that a
compiler may order bitfields in a struct. In the example program I give,
Solaris Sparc gives one result, Intel x86 gives another result (for the
GCC compiler).

Is there a portable way to test how this information is stored? In
particular, will the result of the program below always result in c
being 0x01 or 0x80? Does the compiler allow for padding so that the
result may also be 0x00?

For example:

#include <stdio.h>

struct bitfield {
int b7:1;
int b6:1;
int b5:1;
int b4:1;
int b3:1;
int b2:1;
int b1:1;
int b0:1;
};

union highlow {
struct bitfield bf;
unsigned char c;
};

int main(void)
{
union highlow h;

h.c = 0;
h.bf.b0 = 1;

if (h.c == 0x80) {
printf("LSB machine\n");
} else {
printf("MSB machine\n");
}
printf("c = %02x\n", h.c);
}
 
J

Jack Klein

Hello C Group,

From what I remember, it is implementation dependent the way that a
compiler may order bitfields in a struct. In the example program I give,
Solaris Sparc gives one result, Intel x86 gives another result (for the
GCC compiler).

Is there a portable way to test how this information is stored? In
particular, will the result of the program below always result in c
being 0x01 or 0x80? Does the compiler allow for padding so that the
result may also be 0x00?

The result might be 0x01. It might even be 0x80, but that is rather
unlikely.
For example:

#include <stdio.h>

struct bitfield {
int b7:1;

Note that when used to define bit-field members, plain 'int' is not
necessarily signed int. It may be unsigned int, that is
implementation defined.

Also note that a one-bit signed bit-field is dicey. It can have two
values, but are they 0 and 1 or 0 and -1? Frankly the C standard
leaves this ambiguous, and the behavior of compilers varies.

For single bit bit-fields, it is safest to explicitly used unsigned
int, or, if you have a C99 conforming compiler, _Bool which is an
unsigned integer type.
int b6:1;
int b5:1;
int b4:1;
int b3:1;
int b2:1;
int b1:1;
int b0:1;
};

You seem to assume that this bit-field will occupy exactly 8 bits. No
such requirement or guarantee exists in the C standard. There are
some platforms that will use a whole int or larger type, 16 or 32 or
more bits, not just 8.
union highlow {
struct bitfield bf;
unsigned char c;
};

int main(void)
{
union highlow h;

h.c = 0;
h.bf.b0 = 1;

if (h.c == 0x80) {
printf("LSB machine\n");
} else {
printf("MSB machine\n");
}
printf("c = %02x\n", h.c);
}

Do you actually mean "LSb" and "MSb", that is least and most
significant bit?

Padding has nothing to do with it. Assume an implementation that will
use an int to store the bit-field struct, which is not at all unusual.
So the underlying int has, for example, 32 bits. It is
implementation-defined whether bit-fields are allocated starting with
the most significant or least significant bit, but assume a
little-endian architecture with CHAR_BIT 8 that starts allocating from
the most significant bit.

In that case, the representation of the bit-field interpreted as an
unsigned 32 bit int would be 0x80000000, and it would appear in
memory, from lowest to highest address as 0x00, 0x00, 0x00, 0x80.

Now suppose a bit-endian implementation that starts allocating
bit-fields from the least significant bit. In that case, the
representation of the unsigned bit-field interpreted as a 32-bit
unsigned int would be 0x00000001, and it would appear in memory as
0x00, 0x00, 0x00, 0x01.

You are assuming that because you define a bit-field struct containing
8 bits, and you overlay an unsigned char over its first byte (and you
assume that your char has exactly 8 bits), that all of the 8 bits in
the bit-field will lie within that 8-bit char. There is no guarantee
of that at all.
 
J

Jason Curl

Jack said:
The result might be 0x01. It might even be 0x80, but that is rather
unlikely.


Note that when used to define bit-field members, plain 'int' is not
necessarily signed int. It may be unsigned int, that is
implementation defined.

Also note that a one-bit signed bit-field is dicey. It can have two
values, but are they 0 and 1 or 0 and -1? Frankly the C standard
leaves this ambiguous, and the behavior of compilers varies.


You seem to assume that this bit-field will occupy exactly 8 bits. No
such requirement or guarantee exists in the C standard. There are
some platforms that will use a whole int or larger type, 16 or 32 or
more bits, not just 8.


Do you actually mean "LSb" and "MSb", that is least and most
significant bit?

Yes, LSb and MSb.
Padding has nothing to do with it. Assume an implementation that will
use an int to store the bit-field struct, which is not at all unusual.
So the underlying int has, for example, 32 bits. It is
implementation-defined whether bit-fields are allocated starting with
the most significant or least significant bit, but assume a
little-endian architecture with CHAR_BIT 8 that starts allocating from
the most significant bit.

In that case, the representation of the bit-field interpreted as an
unsigned 32 bit int would be 0x80000000, and it would appear in
memory, from lowest to highest address as 0x00, 0x00, 0x00, 0x80.

Now suppose a bit-endian implementation that starts allocating
bit-fields from the least significant bit. In that case, the
representation of the unsigned bit-field interpreted as a 32-bit
unsigned int would be 0x00000001, and it would appear in memory as
0x00, 0x00, 0x00, 0x01.

I'm assuming CHAR_BIT is 8, as required for POSIX. Must a conforming C
compiler must be consistent in how it allocates the bits?

For example, either 0x00000001, 0x80000000, 0x00008000 or 0x00000080 for
a 32-bit implementation. A 64-bit implementation would then possibly be
similar.

Or is this also in no way guaranteed by the C-standard? <ot> how about
these questions applied the posix standard? said:
You are assuming that because you define a bit-field struct containing
8 bits, and you overlay an unsigned char over its first byte (and you
assume that your char has exactly 8 bits), that all of the 8 bits in
the bit-field will lie within that 8-bit char. There is no guarantee
of that at all.

Rephrasing my question, does the C-standard specify (so that there are a
small number of limited possibilities) how two elements in a union overlay?

Thanks,
Jason.
 

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,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top