I am looking for an expression like sizeofbitfieldmemberinbits()
that
can be calculated by the compiler at build time
The Standard's term for what you are describing is "constant expression":
A constant expression can be evaluated during translation rather than
runtime, and accordingly may be used in any place that a constant may
be.
(C2011, 6.6/2)
You go on to clarify the purpose for which you want to use such a constant expression:
With the assertion I want to check for cases where such truncation not
just might occur, but when actually does.
Note, however, that
For that purpose, the size of the bitfield is secondary. What you actually want is the maximum representable value. For bitfields of signed types, maybe you want the minimum, too.
You don't actually need a constant expression for use in a regular assertion such as you demonstrate (as opposed to a static assertion). The expression in a regular assertion is evaluated at runtime.
On the other hand, some expressions that do not satisfy the Standard's definition of a constant expression may still be computed at translation (compile) time by some implementations.
Points (2) and (3) are fortunate for you, because bitfields have second-class types that are not directly expressible. There are no values of any bitfield type outside the context of a host structure object, and there is no type name with which the effective type of a bitfield can be expressed. And that means there is no constant expression that evaluates to the number of bits or maximum value of a bitfield member, unless it incorporates prior knowledge of that member, because structs (including struct literals) are not among the operands that may appear in a suitable constant expression:
An arithmetic constant expression shall have arithmetic type and shall
only have operands that are integer constants, floating constants,
enumeration constants, character constants, sizeof
expressions whose
results are integer constants, and _Alignof
expressions. Cast
operators in an arithmetic constant expression shall only convert
arithmetic types to arithmetic types, except as part of an operand to
a sizeof
or _Alignof
operator.
(C2011 6.6/8)
After all that, I think the question really boils down to this:
I am not sure if this is guaranteed to work:
assert(someveal <= ((mystruct){.threebits = -1}).threebits);
For unsigned bitfields such as your mystruct.threebits
, it's guaranteed to work in C99 or later. Earlier versions of C do not have compound literals or designated initializers, however, and some C implementations you might run into even today do not conform to C99. On such an implementation, you might instead just define a (maybe const
, maybe static
) instance of your struct in which to record the limits ...
static const struct mystruct mystruct_limits = { -1, -1, -1 };
... and then compare to its members:
assert(someveal <= mystruct_limits.threebits);
Note here that struct member initializers are subject to the same conversions that apply in simple assignment, so as long as the members have unsigned types, the -1s as initializer values are well defined to have the wanted effect.
Note also that although the const
is desirable for the purpose, it was not standardized until C99, either. It was a pretty common extension before C99, though, and you are far less likely to run into a C compiler that rejects const
than one that rejects compound literals.