On Fri, 23 Feb 2007
ma*****@yahoo.com wrote:
>
Although the C90 standard only mentions the use of 'signed int' and
'unsigned int' for bit-fields (use 'int' at your own risk) and C99
adds _Bool.
It seems that most compilers create the size of the bit-field object
from the size used to specify the field.
Could this be considered a defacto standard now (at least for 8 bit
sized bit-fields)?
I don't exactly see what you mean. I think you are saying that on
"most" compilers, the structure definition
struct {
unsigned char x:4;
unsigned char y:4;
} nibs;
yields a struct with a size of 8 bits, arranged as xxxxyyyy, but
struct {
unsigned int x:4;
unsigned int y:4;
} nibs;
yields a struct with a size of 32 bits, arranged as
xxxxyyyy000000000000000000000000.
This is indeed true for Keil's compiler:
http://www.keil.com/support/docs/928.htm
and GCC and yes, probably most modern compilers. However, there's
an extra wrinkle that you didn't mention: On "most" compilers, a
bitfield of declared type T will never span memory chunks of
size T. (The real type of a bitfield is simply a "bit-field type"; but
like you, I'm talking about the "unsigned char" or whatever that you
use in the struct definition.)
For example, an "unsigned char" bitfield will never span two bytes;
padding bits will be inserted if necessary to justify it in its own
byte. Therefore, the struct definition
struct {
unsigned char x : 5;
unsigned char y : 5;
} nabs;
will correspond on "most" compilers to xxxxx000yyyyy000, while
struct {
unsigned short x : 5;
unsigned short y : 5;
} nabs;
will correspond to xxxxxyyyyy000000.
[Soapbox]
Wouldn't it had more sense for the compiler folks to just add up the
specified number bits and use the smallest integer type that would fit
so code could follow the standard?
It would make about as much sense, I guess. I don't see how it would
make /more/ sense. If you care about that kind of micro-optimization,
you probably welcome the extra tiny bit of control over alignment given
to you by the "de-facto" standard.
The issue may originally have been that unaligned memory accesses are
terribly slow on most platforms; therefore, it makes sense to allow the
programmer to force byte-alignment or word-alignment with a minimum of
fuss. (C99 introduced anonymous bitfields to deal with the same issue.)
The issue now is certainly compatibility with other compilers. Peer
pressure is a strong force in the compiler field.
N869 section 6.7.2.1#9 seems to encourage the "de-facto" behavior:
[#9] An implementation may allocate any addressable storage
unit large enough to hold a bit-field. 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.
Obviously programmers want to use bit-field objects that may be
smaller or larger than standard integer size shouldn't the standard
support that.
No. If there's no Standard support for 128-bit integer math, it
seems pretty silly to require implementations to support integer
math on bitfields of type "signed int foo : 128". That would put a
huge burden on implementors to deal with arbitrarily-wide integer
math, while making users jump through silly hoops to get at it.
Some compilers support "long long" bitfields. Interestingly, GCC
will pack "long long" bitfields across 8-byte boundaries, and will pad
them only to 4-byte boundaries (e.g., a struct containing two fields
of type "long long : 4" will have size 32 bits, not 64 bits). That
seems needlessly inconsistent to me, but I don't know what other
compilers do. I'll find out what ours does on Monday. ;)
-Arthur,
one of those compiler folks