This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: Question on structure bit fields and portability?
- From: John Love-Jensen <eljay at adobe dot com>
- To: <mbumble at cpinternet dot com>, <gcc-help at gcc dot gnu dot org>
- Date: Mon, 12 May 2003 07:19:00 -0500
- Subject: Re: Question on structure bit fields and portability?
Hi Marc,
>If one uses or expects the gcc compiler across a variety of platforms, does
that help alleviate the portability problem with bit fields?
No. The portability problem is that bit-fields are strongly affected by
architecture, including endian-ness and data width. A word on one machine
might be 16-bit, and 32-bit on another, and 64-bit on a third -- that'll
affect bit-fields too.
>Why is it that compilers do not automatically solve the bit field problem
consistently for each given architecture?
Because architectures are inconsistent with one another, so the problem
cannot be solved automatically.
The automatic solution is the one where there are no guarantees, because
padding may be different -- this is the automatic solution that you are
taking exception with.
>Also, if bit fields are a problem, what is most eloquent solution to solving
the bit reading problem in terms of efficiency and readability?
Make sure the code is liberally annotated with "DANGER: PLATFORM SPECIFIC
CODE" messages.
Or avoid using platform specific code. (Which is next to impossible for
low-level hardware interfacing.)
If you're not doing low-level hardware interface code, you may very well not
need bit fields. In C++, you can roll your own explicitly controlled
quasi-bit-fields through accessor / mutator functions:
#include <stdint.h> // C99 header; <cstdint> for C++?
class Foo {
// m : 0..6 -- 7-bits for x
// m : 7..13 -- 7-bits for y
// m : 14..16 -- 3-bits for z
// m : 17..20 -- 4-bits for hit points
// m : 21..25 -- 5-bits for armor class
uint32_t m;
public:
Foo() : m(0) { }
uint32_t getX() { return m & 0x7F; }
uint32_t getY() { return (m >> 7) & 0x7F; }
uint32_t getZ() { return (m >> 14) & 0x07; }
uint32_t getHP() { return (m >> 17) & 0x0F; }
uint32_t getAC() { return (m >> 21) & 0x1F; }
void setX(uint32_t x) { m = (m & ~0x7F) | (x & 0x7F); }
void setY(uint32_t y) { m = (m & ~(0x7F << 7)) | ((x & 0x7F) << 7); }
void setZ(uint32_t y) { m = (m & ~(0x07 << 14)) | ((x & 0x07) << 14); }
void setHP(uint32_t y) { m = (m & ~(0x0F << 17)) | ((x & 0x0F) << 17); }
void setAC(uint32_t y) { m = (m & ~(0x1F << 21)) | ((x & 0x1F) << 21); }
};
Note: not tested, there may be typos. It may be wise to cast the masking
constants to uint32_t.
--Eljay