I have the following C listing:
static const int constant = (0 | ((((1 << 6) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1) << ((((0 + 8) + 8) + 3) + 7))) | ((((1 << 7) - 1) << (((0 + 8) + 8) + 3)) & ((0) << (((0 + 8) + 8) + 3))) | ((((1 << 3) - 1) << ((0 + 8) + 8)) & ((0) << ((0 + 8) + 8))) | ((((1 << 8) - 1) << 0) & ((1) << 0)));
int main(int argc, char** argv)
{
return constant;
}
When I am trying to compile this with GCC-9.1 using this command line:
gcc-9 -Werror -Wpedantic main.c
I am getting this error:
main.c:1:29: error: initializer element is not a constant expression [-Werror=pedantic]
Why is that? Is this a compiler bug? Clearly, constant
is initialized with a constant expression.
I am getting this error:
main.c:1:29: error: initializer element is not a constant expression [-Werror=pedantic]
Why is that? Is this a compiler bug? Clearly, constant is initialized with a constant expression.
"Constant expression" is a defined term in the language standard. I suspect that GCC is using it that way, as the standard does require your initializer to be a constant expression in that sense. Certainly the evaluation of your code needs to be performed in that light.
There are two language constraints on constant expressions:
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.
and
Each constant expression shall evaluate to a constant that is in the range of representable values for its type.
The former is not a problem for you. The latter, however, is an issue on C implementations where type int
has 31 or fewer value bits (including GCC on most platforms). Consider in particular this sub-expression:
(((1 << 6) - 1) << ((((0 + 8) + 8) + 3) + 7))
... but for sanity, let's remove some unnecessary parentheses and simplify the right-hand side of the outer <<
to get this, which preserves the relevant characteristics:
((1 << 6) - 1) << 26
All the individual numeric constants have type int
, therefore so also do all the intermediate results (where the "26" in the simplified version corresponds to such an intermediate result in the original expression). The arithmetically-correct result for that left shift requires at least 32 value bits, and because your int
(probably) doesn't have that many, since one bit is reserved for the sign, the behavior is undefined.
As such, there is no compiler bug here, though you might have a grounds for a quality of implementation complaint. Likewise, no compiler that accepts the code without warning or error is for that reason buggy. In a different sense, your code does violate a language constraint, and in that sense the compiler is obligated to emit a diagnostic, although the one it has chosen seems misleading.
Furthermore, others' comments on the question seem to confirm that the overflow is correlated with the error, since changing the called-out expression from using (1 << 6)
to either (1 << 5)
or (1u << 6)
resolves the error for others who could reproduce it. Both yield overall expression without any sub-expressions that have undefined behavior.
Note well that it is almost always better to avoid signed integer types when you are doing bitwise manipulation. As such, neglecting any impact on the larger program from which this was drawn, I would be inclined to rewrite your example program as
static const unsigned int constant = (0
| ((((1u << 6) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1u) << ((((0 + 8) + 8) + 3) + 7)))
| ((((1u << 7) - 1) << (((0 + 8) + 8) + 3)) & ((0u) << (((0 + 8) + 8) + 3)))
| ((((1u << 3) - 1) << ((0 + 8) + 8)) & ((0u) << ((0 + 8) + 8)))
| ((((1u << 8) - 1) << 0) & ((1u) << 0)));
int main(void) {
// There's a potential issue with the conversion of the return value, too, but it
// does not affect the particular expression at issue here.
return constant;
}
Note that the type of the result of a bitwise shift is determined by the type of its left-hand operand only.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With