Why this constant expression is not constantError “initializer element is not constant” when trying to initialize variable with constWith arrays, why is it the case that a[5] == 5[a]?Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)?Why are elementwise additions much faster in separate loops than in a combined loop?Why static const members cannot appear in a constant expression like 'switch'Why is ZLIB uncompress hanging?Why does the C preprocessor interpret the word “linux” as the constant “1”?Global reach of char *argv[ ] and int argc C++int main(int argc, const char * argv[]) AND file inputC struct - cannot be definedVigénere Cipher in C
how to convert Timestring to seconds
Minimizing medical costs with HSA
Why did C++11 make std::string::data() add a null terminating character?
Is it possible that Curiosity measured its own methane or failed doing the spectrometry?
Should I increase my 401k contributions, or increase my mortgage payments
Why do we need a bootloader separate than our application program in MCU's?
What does this value mean in a BJT datasheet?
How come having a Deathly Hallow is not a big deal?
About opening an LLC with little to report in the beginning
How to figure out layers of the atmosphere?
Was Wolfgang Unzicker the last Amateur GM?
How frequently do Russian people still refer to others by their patronymic (отчество)?
Two queries on triangles, the sides of which have rational lengths
Can a wizard delay learning new spells from leveling up to learn different spells later?
How should I present a resort brochure in my general fiction?
Do intermediate subdomains need to exist?
Do I need to be legally qualified to install a Hive smart thermostat?
Convenience stores in India
Using Sed to add counter to keyword
Does Evolution Sage proliferate Blast Zone when played?
What do you call the angle of the direction of an airplane?
Can 4 Joy cons connect to the same Switch?
What is the addition in the re-released version of Avengers: Endgame?
Bypass with wrong cvv of debit card and getting OTP
Why this constant expression is not constant
Error “initializer element is not constant” when trying to initialize variable with constWith arrays, why is it the case that a[5] == 5[a]?Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)?Why are elementwise additions much faster in separate loops than in a combined loop?Why static const members cannot appear in a constant expression like 'switch'Why is ZLIB uncompress hanging?Why does the C preprocessor interpret the word “linux” as the constant “1”?Global reach of char *argv[ ] and int argc C++int main(int argc, const char * argv[]) AND file inputC struct - cannot be definedVigénere Cipher in C
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
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.
c gcc
|
show 9 more comments
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.
c gcc
2
@PM77-1: That's not the issue. The question isn't whether the expressionconstantis a constant expression, it's whether its initializer is a constant expression.
– Keith Thompson
8 hours ago
1
Could it be that some subexpression overflows the range ofint? (Note that clang doesn't complain.) Could be a gcc bug.
– Keith Thompson
8 hours ago
1
@vaigult I can' not reproduce the error.
– Vlad from Moscow
8 hours ago
4
You have UB as a result of an overflowing left-shift, so this example does not demonstrate a compiler bug. I'm not sure whether that fully explains the issue, however. Does GCC 9.1 still reject the code if you change the(1 << 6)to(1 << 5)?
– John Bollinger
7 hours ago
3
@JohnBollinger: For me, if I change the first (only)(1 << 6)to(1 << 5), the error message goes away. The term becomes((((1 << 5) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1) << ((((0 + 8) + 8) + 3) + 7)))which avoids shifting1left by 32 (the left shifting in total is 31) when you change 6 to 5. That's probably a mix of 'good catch' and 'poor message' by the compiler.
– Jonathan Leffler
7 hours ago
|
show 9 more comments
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.
c gcc
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.
c gcc
c gcc
asked 8 hours ago
ivaigultivaigult
3,2502 gold badges19 silver badges43 bronze badges
3,2502 gold badges19 silver badges43 bronze badges
2
@PM77-1: That's not the issue. The question isn't whether the expressionconstantis a constant expression, it's whether its initializer is a constant expression.
– Keith Thompson
8 hours ago
1
Could it be that some subexpression overflows the range ofint? (Note that clang doesn't complain.) Could be a gcc bug.
– Keith Thompson
8 hours ago
1
@vaigult I can' not reproduce the error.
– Vlad from Moscow
8 hours ago
4
You have UB as a result of an overflowing left-shift, so this example does not demonstrate a compiler bug. I'm not sure whether that fully explains the issue, however. Does GCC 9.1 still reject the code if you change the(1 << 6)to(1 << 5)?
– John Bollinger
7 hours ago
3
@JohnBollinger: For me, if I change the first (only)(1 << 6)to(1 << 5), the error message goes away. The term becomes((((1 << 5) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1) << ((((0 + 8) + 8) + 3) + 7)))which avoids shifting1left by 32 (the left shifting in total is 31) when you change 6 to 5. That's probably a mix of 'good catch' and 'poor message' by the compiler.
– Jonathan Leffler
7 hours ago
|
show 9 more comments
2
@PM77-1: That's not the issue. The question isn't whether the expressionconstantis a constant expression, it's whether its initializer is a constant expression.
– Keith Thompson
8 hours ago
1
Could it be that some subexpression overflows the range ofint? (Note that clang doesn't complain.) Could be a gcc bug.
– Keith Thompson
8 hours ago
1
@vaigult I can' not reproduce the error.
– Vlad from Moscow
8 hours ago
4
You have UB as a result of an overflowing left-shift, so this example does not demonstrate a compiler bug. I'm not sure whether that fully explains the issue, however. Does GCC 9.1 still reject the code if you change the(1 << 6)to(1 << 5)?
– John Bollinger
7 hours ago
3
@JohnBollinger: For me, if I change the first (only)(1 << 6)to(1 << 5), the error message goes away. The term becomes((((1 << 5) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1) << ((((0 + 8) + 8) + 3) + 7)))which avoids shifting1left by 32 (the left shifting in total is 31) when you change 6 to 5. That's probably a mix of 'good catch' and 'poor message' by the compiler.
– Jonathan Leffler
7 hours ago
2
2
@PM77-1: That's not the issue. The question isn't whether the expression
constant is a constant expression, it's whether its initializer is a constant expression.– Keith Thompson
8 hours ago
@PM77-1: That's not the issue. The question isn't whether the expression
constant is a constant expression, it's whether its initializer is a constant expression.– Keith Thompson
8 hours ago
1
1
Could it be that some subexpression overflows the range of
int? (Note that clang doesn't complain.) Could be a gcc bug.– Keith Thompson
8 hours ago
Could it be that some subexpression overflows the range of
int? (Note that clang doesn't complain.) Could be a gcc bug.– Keith Thompson
8 hours ago
1
1
@vaigult I can' not reproduce the error.
– Vlad from Moscow
8 hours ago
@vaigult I can' not reproduce the error.
– Vlad from Moscow
8 hours ago
4
4
You have UB as a result of an overflowing left-shift, so this example does not demonstrate a compiler bug. I'm not sure whether that fully explains the issue, however. Does GCC 9.1 still reject the code if you change the
(1 << 6) to (1 << 5)?– John Bollinger
7 hours ago
You have UB as a result of an overflowing left-shift, so this example does not demonstrate a compiler bug. I'm not sure whether that fully explains the issue, however. Does GCC 9.1 still reject the code if you change the
(1 << 6) to (1 << 5)?– John Bollinger
7 hours ago
3
3
@JohnBollinger: For me, if I change the first (only)
(1 << 6) to (1 << 5), the error message goes away. The term becomes ((((1 << 5) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1) << ((((0 + 8) + 8) + 3) + 7))) which avoids shifting 1 left by 32 (the left shifting in total is 31) when you change 6 to 5. That's probably a mix of 'good catch' and 'poor message' by the compiler.– Jonathan Leffler
7 hours ago
@JohnBollinger: For me, if I change the first (only)
(1 << 6) to (1 << 5), the error message goes away. The term becomes ((((1 << 5) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1) << ((((0 + 8) + 8) + 3) + 7))) which avoids shifting 1 left by 32 (the left shifting in total is 31) when you change 6 to 5. That's probably a mix of 'good catch' and 'poor message' by the compiler.– Jonathan Leffler
7 hours ago
|
show 9 more comments
1 Answer
1
active
oldest
votes
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.
Tl;dr Why does an expression that would produce UB affect the compiler output? Is that a part of UB cases?
– machine_1
5 hours ago
The error message is correct, but it could be improved by explaining why the expression is not a constant expression (in this case, that a subexpression overflows).
– Keith Thompson
5 hours ago
@machine_1, in general, "undefined behavior" applies to the combination of program and C implementation. It can manifest either at translation (compile) time or at run time. Certain undefined behaviors make sense only at run time -- for instance, if they are contingent on externally-provided data -- but this is not such a case.
– John Bollinger
5 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56855913%2fwhy-this-constant-expression-is-not-constant%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
Tl;dr Why does an expression that would produce UB affect the compiler output? Is that a part of UB cases?
– machine_1
5 hours ago
The error message is correct, but it could be improved by explaining why the expression is not a constant expression (in this case, that a subexpression overflows).
– Keith Thompson
5 hours ago
@machine_1, in general, "undefined behavior" applies to the combination of program and C implementation. It can manifest either at translation (compile) time or at run time. Certain undefined behaviors make sense only at run time -- for instance, if they are contingent on externally-provided data -- but this is not such a case.
– John Bollinger
5 hours ago
add a comment |
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.
Tl;dr Why does an expression that would produce UB affect the compiler output? Is that a part of UB cases?
– machine_1
5 hours ago
The error message is correct, but it could be improved by explaining why the expression is not a constant expression (in this case, that a subexpression overflows).
– Keith Thompson
5 hours ago
@machine_1, in general, "undefined behavior" applies to the combination of program and C implementation. It can manifest either at translation (compile) time or at run time. Certain undefined behaviors make sense only at run time -- for instance, if they are contingent on externally-provided data -- but this is not such a case.
– John Bollinger
5 hours ago
add a comment |
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.
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.
edited 6 hours ago
answered 6 hours ago
John BollingerJohn Bollinger
92.1k8 gold badges47 silver badges90 bronze badges
92.1k8 gold badges47 silver badges90 bronze badges
Tl;dr Why does an expression that would produce UB affect the compiler output? Is that a part of UB cases?
– machine_1
5 hours ago
The error message is correct, but it could be improved by explaining why the expression is not a constant expression (in this case, that a subexpression overflows).
– Keith Thompson
5 hours ago
@machine_1, in general, "undefined behavior" applies to the combination of program and C implementation. It can manifest either at translation (compile) time or at run time. Certain undefined behaviors make sense only at run time -- for instance, if they are contingent on externally-provided data -- but this is not such a case.
– John Bollinger
5 hours ago
add a comment |
Tl;dr Why does an expression that would produce UB affect the compiler output? Is that a part of UB cases?
– machine_1
5 hours ago
The error message is correct, but it could be improved by explaining why the expression is not a constant expression (in this case, that a subexpression overflows).
– Keith Thompson
5 hours ago
@machine_1, in general, "undefined behavior" applies to the combination of program and C implementation. It can manifest either at translation (compile) time or at run time. Certain undefined behaviors make sense only at run time -- for instance, if they are contingent on externally-provided data -- but this is not such a case.
– John Bollinger
5 hours ago
Tl;dr Why does an expression that would produce UB affect the compiler output? Is that a part of UB cases?
– machine_1
5 hours ago
Tl;dr Why does an expression that would produce UB affect the compiler output? Is that a part of UB cases?
– machine_1
5 hours ago
The error message is correct, but it could be improved by explaining why the expression is not a constant expression (in this case, that a subexpression overflows).
– Keith Thompson
5 hours ago
The error message is correct, but it could be improved by explaining why the expression is not a constant expression (in this case, that a subexpression overflows).
– Keith Thompson
5 hours ago
@machine_1, in general, "undefined behavior" applies to the combination of program and C implementation. It can manifest either at translation (compile) time or at run time. Certain undefined behaviors make sense only at run time -- for instance, if they are contingent on externally-provided data -- but this is not such a case.
– John Bollinger
5 hours ago
@machine_1, in general, "undefined behavior" applies to the combination of program and C implementation. It can manifest either at translation (compile) time or at run time. Certain undefined behaviors make sense only at run time -- for instance, if they are contingent on externally-provided data -- but this is not such a case.
– John Bollinger
5 hours ago
add a comment |
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56855913%2fwhy-this-constant-expression-is-not-constant%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
@PM77-1: That's not the issue. The question isn't whether the expression
constantis a constant expression, it's whether its initializer is a constant expression.– Keith Thompson
8 hours ago
1
Could it be that some subexpression overflows the range of
int? (Note that clang doesn't complain.) Could be a gcc bug.– Keith Thompson
8 hours ago
1
@vaigult I can' not reproduce the error.
– Vlad from Moscow
8 hours ago
4
You have UB as a result of an overflowing left-shift, so this example does not demonstrate a compiler bug. I'm not sure whether that fully explains the issue, however. Does GCC 9.1 still reject the code if you change the
(1 << 6)to(1 << 5)?– John Bollinger
7 hours ago
3
@JohnBollinger: For me, if I change the first (only)
(1 << 6)to(1 << 5), the error message goes away. The term becomes((((1 << 5) - 1) << ((((0 + 8) + 8) + 3) + 7)) & ((1) << ((((0 + 8) + 8) + 3) + 7)))which avoids shifting1left by 32 (the left shifting in total is 31) when you change 6 to 5. That's probably a mix of 'good catch' and 'poor message' by the compiler.– Jonathan Leffler
7 hours ago