C defines at least 3 levels of "constant expression":
- constant expression (unqualified)
- arithmetic constant expression
- integer constant expression
6.6 paragraph 3 reads:
Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.
So does this mean 1,2
is not a constant expression?
Paragraph 8 reads:
An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer constants, floating constants, enumeration constants, character constants, and sizeof 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 operator whose result is an integer constant.
What are the operands in (union { uint32_t i; float f; }){ 1 }.f
? If 1
is the operand, then this is presumably an arithmetic constant expression, but if { 1 }
is the operand, then it's clearly not.
Edit: Another interesting observation: 7.17 paragraph 3 requires the result of offsetof
to be an integer constant expression of type size_t
, but the standard implementations of offsetof
, as far as I can tell, are not required to be integer constant expressions by the standard. This is of course okay since an implementation is allowed (under 6.6 paragraph 10) to accept other forms of constant expressions, or implement the offsetof
macro as __builtin_offsetof
rather than via pointer subtraction. The essence of this observation, though, is that if you want to use offsetof
in a context where an integer constant expression is required, you really need to use the macro provided by the implementation and not roll your own.
Based on your reading,
1,2
isn't a constant expression. I don't know why it isn't, just that I agree with you that it isn't (despite the fact that it probably should be).6.5.2 specifies compound literals as a postfix operator. So in
The operands are
(union { uint32_t i; float f; }){ 1 }
andf
to the.
operator. It is not an arithmetic constant expression, since the first argument is aunion
type, but it is a constant expression.UPDATE: I was basing this on a different interpretation of the standard.
My previous reasoning was that
(union { uint32_t i; float f; }){ 1 }.f
met the criteria for a constant expression, and was therefore a constant expression. I still think it meets the criteria for a constant expression (6.6 paragraph 3) but that it is not any of the standard types of constant expressions (integer, arithmetic, or address) and is therefore only subject to being a constant expression by 6.6 paragraph 10, which allows implementation-defined constant expressions.I'd also been meaning to get to your edit. I was going to argue that the "hack" implementation of
offsetof
was a constant expression, but I think it's the same as above: it meets the criteria for a constant expression (and possibly an address constant) but is not an integer constant expression, and is therefore invalid outside of 6.6 paragraph 10.