Re: Portability issues (union, bitfields)
- From: Eric Sosman <esosman@xxxxxxxxxxxxxxxxxxxx>
- Date: Thu, 05 Nov 2009 08:28:05 -0500
Noob wrote:
Eric Sosman wrote:
Noob wrote:[... bit-fields in a struct, union-punned with unsigned char ...]I don't believe so. He assumes that an int is at least 24
1. The definition of bitmap_t seems to imply that the author thinks
(unsigned int) is at least (or exactly) 32-bits wide.
bits wide, but I don't see an assumption of any specific >=24-bit
width.
You are correct when you say the code only assumes width >= 24, but IMO,
it is clear that, in the author's mind, width == 32 and he is padding
the struct "by hand" to fill the 32 bits.
Yes, the author almost certainly had "thirty-two" somewhere
in the back of his brain. But since the code makes no use of the
24-bit padding field, I'm still not sure that the assumption of
a 32-bit int is really relevant.
I don't think it has ever crossed the author's mind that an int could be
24-bits wide. (IMHO, not many people who call themselves "C programmers"
are aware than an int could be 24-bits wide.)
It has been many years since I used a machine with 24-bit
words (four six-bit characters per word). I doubt we'll see
such things again in general-purpose machines. (Special-purpose
hardware may be a different story.)
Since a bit-field cannot (portably) be wider than an int,
and since an int can be as narrow as sixteen bits, it's possible
that the attempt to declare a 24-bit field may fail.
What does it mean for a declaration to fail?
Compiler warning then UB?
With a 16-bit int, say, the `unsigned int reserved : 24;'
struct member would be an invalid declaration. It would "fail"
in the same way that `int array[-42];' would "fail."
The exact requirement is that the specified width shall not
exceed the width of the bit-field's base type, and it's in a
Constraints section (6.7.2.1p3) so a diagnostic is required for
violations. 6.7.2.1p4 goes on to list the allowable base types:
_Bool (C99 only), the two flavors of int, and "some other
implementation-defined type." No diagnostic is required for
the use of base types beyond the required three -- but the
implementation is not obliged to accept them, either.
As far as I can see, there is no 100% portable way to
specify a 24-bit bit-field. The widest 100% portable base type
is int, and int could be as narrow as 16 bits, and you're stuck.
You could specify `unsigned int reserved : 24;' and hope int is
wide enough, or you could write `unsigned long reserved : 24;'
and hope the implementation accepts long (necessarily >=32 bits),
but your hopes might be dashed either way.
2. (I'm not sure about this one.) foo is written to using the map field,The value of foo.uc is unspecified. Since unsigned char has no
then read from using a different field. This specific instance might be
OK, because uc's type is unsigned char?
trap representations you won't get UB by fetching it, but there's
no telling what value you'll get.
Do you agree that, on some platforms, the bits in the union will map to
the bits of foo.uc? Do you say its value is unspecified because this
might not be the case (point 3) or for some other reason?
To the first, yes. To the second, I'm relying on 6.2.6.1p7:
When a value is stored in a member of an object of union
type, the bytes of the object representation that do not
correspond to that member but do correspond to other
members take unspecified values, [...]
In the case at hand, values are stored in the struct member of
a union, and then an unsigned char member is fetched. We know
that the struct's eight 1-bit bit-fields occupy the first
"addressable storage unit" in the struct, and that the ASU is
the first thing in that struct and hence the first thing in the
union. We also know that the unsigned char is the first thing
in the union -- but we don't know how big the ASU is, nor which
of its bits hold the bit-fields. The union's first byte -- the
unsigned char fetched at the end -- might be in an unused part
of the ASU, and the values of the bits that correspond to no
member of the struct are unspecified.
That's how I understand it, anyhow.
3. The code seems to assume field "aa" maps to the least-significant bitThe assumption is unwarranted, but I'm not sure the code
of the parameter (bit 0), "bb" maps to bit 1, etc.
really makes the assumption. We'd have to know something about
the expected/intended inputs and outputs to know what the
assumptions are. Maybe this code is used to discover something
about the way a particular compiler lays out bit-fields?
You're right, I did leave out some critical piece of information (a
comment) which stated :
/* Bit 0 : aa is used for X
Bit 1 : bb is used for Y
... */
The bit mask is used by the library user to request specific features.
For example, if the user wants features aa and cc, then he calls
frob(1<<0 | 1<<2);
Then frob does the little dance with the bit field, but needs to pass a
bit mask down the chain. The obvious answer would be to never introduce
any bit fields, and to work with the masks all the way (as was done
before), but (IMO) the author is convinced that the new code is easier
to maintain because the meaning of each bit is spelled out in the
field's name. This happens to work because GCC packs the bits least
significant-bit-first, but it will break with a vengeance if we ever
move to a different compiler, or if GCC suddenly changes the bit order
(though that seems rather unlikely).
He could keep using bit-fields (aside from the problematic
24-bit field, which he doesn't seem to need anyhow). It's the
type-punning that makes the trouble: He goes to all this trouble
to set and clear the bit-fields without assuming anything about
their order, and then he messes it up with a different assumption.
Why not just pass the struct and its bit-fields around? (And why
not jettison that 24-bit element, if it's not used?)
--
Eric Sosman
esosman@xxxxxxxxxxxxxxxxxxxx
.
- Follow-Ups:
- Re: Portability issues (union, bitfields)
- From: John Temples
- Re: Portability issues (union, bitfields)
- References:
- Portability issues (union, bitfields)
- From: Noob
- Re: Portability issues (union, bitfields)
- From: Eric Sosman
- Re: Portability issues (union, bitfields)
- From: Noob
- Portability issues (union, bitfields)
- Prev by Date: Re: Question on structs
- Next by Date: Re: gprof - on a server app
- Previous by thread: Re: Portability issues (union, bitfields)
- Next by thread: Re: Portability issues (union, bitfields)
- Index(es):
Relevant Pages
|