
Martin Bonner wrote:
----Original Message---- From: Emile Cormier
The bitfield mechanism relies on this assumption: Unions of non-polymorphic, non-derived objects, having the exact same underlying data member type, will have the same size as this underlying data member type. I'm no language lawyer, so please let me know if this is a safe and portable assumption.
I'm not quite sure what you mean, but given: struct a { unsigned char ch; }; struct b { unsigned char ch; }; union u { a theA; b theB }; then you are not guaranteed that sizeof(u) == sizeof(unsigned char).
On word addressed machines (which /are/ still being built), it is almost certain that the minimum size for a struct is a complete word. This is because the C and C++ standards effectively promise that pointers to structs are all of the same size (the size of a pointer-to-struct does not depend on the contents of the struct). It is desirable that a pointer-to-struct be the smaller, cheaper-to-dereference pointer to word (rather than the larger more-expensive-to-dereference pointer to char), so the smallest struct has to occupy a whole word.
HOWEVER, if your structures and unions are using unsigned char, why not just use "unsigned char *" instead? If you are using unsigned short (or longer types), then you are almost certain to be safe. It is not guaranteed by the standard; a compiler /can/ pad all structures to 256 bits if it wants to, but in practise compilers don't.
I've just run some tests on an ARM platform (arm-elf-gcc), and sizeof(u) from Martin's example above always returns 4 regardless of whether char, short, or long are used. If I use the -fpack-struct option, then sizeof(u) becomes 1/2/4 for char/short/long respectively. On gcc x86, i get sizeof(u) = 1/2/4 for char/short/long without -fpack-struct. Martin is on to something about using pointers. The pointer already "knows" how to access char/short/long integers. The disadvantage of using pointers is their storage space and the indirection to the actual data. For example, a system with 50 8-bit registers would require 50*sizeof(char*) bytes to store the pointers. I'd prefer that the bitfield manipulate the data directly, so that, for example: union hardware_reg { bitfield<uint16_t, 4, 8> bf1; }; hardware_reg a; a.bf = val; is equivalent to: uint16_t a; a = (a & 0xfff0) | ( (val & 0x000f) << 4 ); rather than: uint16_t a; uint16_t* p = &a; *p = (*p & 0xfff0) | ( (val & 0x000f) << 4 ); I've got another way of doing bitfields up my sleeve that is not as syntactically pretty as C++ bitfields, but may be much more portable. I'll let you know when I've uploaded "version 2" to the Boost vault.