Why does a const int not get optimized by the compiler (through the symbol table) if another pointer points...
This is a follow up on an answer in this question: What kind of optimization does const offer in C/C++? (if any)
In the top voted answer, the following is stated:
When you declare a const in your program,
int const x = 2;
Compiler can optimize away this const by not providing storage to this variable rather add it in symbol table. So, subsequent read just need indirection into the symbol table rather than instructions to fetch value from memory.
NOTE:- If you do something like below:-
const int x = 1;
const int* y = &x;
Then this would force compiler to allocate space for 'x'. So, that degree of optimization is not possible for this case.
Why is this the case? Looks like you will never be able to change x anyway, no?
c++ pointers reference const compiler-optimization
add a comment |
This is a follow up on an answer in this question: What kind of optimization does const offer in C/C++? (if any)
In the top voted answer, the following is stated:
When you declare a const in your program,
int const x = 2;
Compiler can optimize away this const by not providing storage to this variable rather add it in symbol table. So, subsequent read just need indirection into the symbol table rather than instructions to fetch value from memory.
NOTE:- If you do something like below:-
const int x = 1;
const int* y = &x;
Then this would force compiler to allocate space for 'x'. So, that degree of optimization is not possible for this case.
Why is this the case? Looks like you will never be able to change x anyway, no?
c++ pointers reference const compiler-optimization
The "compiler" seems to be an important part in this.
– Ted Lyngmo
Nov 17 '18 at 5:12
1
But how do you usey
? Otherwise the compiler could optimize away both? And depending on how you usey
then it might be able to do it anyway.
– Some programmer dude
Nov 17 '18 at 5:17
1
Edited the title to include compiler
– kop_padawan
Nov 17 '18 at 5:22
3
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
– Peter
Nov 17 '18 at 7:18
add a comment |
This is a follow up on an answer in this question: What kind of optimization does const offer in C/C++? (if any)
In the top voted answer, the following is stated:
When you declare a const in your program,
int const x = 2;
Compiler can optimize away this const by not providing storage to this variable rather add it in symbol table. So, subsequent read just need indirection into the symbol table rather than instructions to fetch value from memory.
NOTE:- If you do something like below:-
const int x = 1;
const int* y = &x;
Then this would force compiler to allocate space for 'x'. So, that degree of optimization is not possible for this case.
Why is this the case? Looks like you will never be able to change x anyway, no?
c++ pointers reference const compiler-optimization
This is a follow up on an answer in this question: What kind of optimization does const offer in C/C++? (if any)
In the top voted answer, the following is stated:
When you declare a const in your program,
int const x = 2;
Compiler can optimize away this const by not providing storage to this variable rather add it in symbol table. So, subsequent read just need indirection into the symbol table rather than instructions to fetch value from memory.
NOTE:- If you do something like below:-
const int x = 1;
const int* y = &x;
Then this would force compiler to allocate space for 'x'. So, that degree of optimization is not possible for this case.
Why is this the case? Looks like you will never be able to change x anyway, no?
c++ pointers reference const compiler-optimization
c++ pointers reference const compiler-optimization
edited Nov 17 '18 at 5:21
kop_padawan
asked Nov 17 '18 at 5:09
kop_padawankop_padawan
327
327
The "compiler" seems to be an important part in this.
– Ted Lyngmo
Nov 17 '18 at 5:12
1
But how do you usey
? Otherwise the compiler could optimize away both? And depending on how you usey
then it might be able to do it anyway.
– Some programmer dude
Nov 17 '18 at 5:17
1
Edited the title to include compiler
– kop_padawan
Nov 17 '18 at 5:22
3
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
– Peter
Nov 17 '18 at 7:18
add a comment |
The "compiler" seems to be an important part in this.
– Ted Lyngmo
Nov 17 '18 at 5:12
1
But how do you usey
? Otherwise the compiler could optimize away both? And depending on how you usey
then it might be able to do it anyway.
– Some programmer dude
Nov 17 '18 at 5:17
1
Edited the title to include compiler
– kop_padawan
Nov 17 '18 at 5:22
3
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
– Peter
Nov 17 '18 at 7:18
The "compiler" seems to be an important part in this.
– Ted Lyngmo
Nov 17 '18 at 5:12
The "compiler" seems to be an important part in this.
– Ted Lyngmo
Nov 17 '18 at 5:12
1
1
But how do you use
y
? Otherwise the compiler could optimize away both? And depending on how you use y
then it might be able to do it anyway.– Some programmer dude
Nov 17 '18 at 5:17
But how do you use
y
? Otherwise the compiler could optimize away both? And depending on how you use y
then it might be able to do it anyway.– Some programmer dude
Nov 17 '18 at 5:17
1
1
Edited the title to include compiler
– kop_padawan
Nov 17 '18 at 5:22
Edited the title to include compiler
– kop_padawan
Nov 17 '18 at 5:22
3
3
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
– Peter
Nov 17 '18 at 7:18
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
– Peter
Nov 17 '18 at 7:18
add a comment |
1 Answer
1
active
oldest
votes
IMHO, Peter provided the explanation in his comment:
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
and this is exactly what I think too.
The const
in C++ is a little bit confusing. It looks like the abbreviation of “constant” but actually it means “read-only”.
This in mind, I never wondered why the following code is legal in C:
enum { N = 3 };
static int a[N]; /* legal in C: N is a constant. */
but this not:
const int n = 3;
static int b[n]; /* illegal in C: n is a read-only variable */
When I switched to C++, I assumed the above for C++ until I realized in a discussion with a colleague that I was wrong. (Not that this broke any written code of mine, but I hate it to be wrong.) ;-)
const int n = 3;
static int b[n]; // legal in C++
and Const propagation is the technique which makes it legal.
However, even with const propagation const int x;
is still a read-only variable which might be addressed.
The OP provided a link about this topic (which might explain it even better than above):
SO: why the size of array as a constant variable is not allowed in C but allowed in C++?
To make this a ful-featured answer I tried to prepare a sample which illustrates the differences:
#include <iostream>
const int x1 = 1;
static const int x1s = 11;
extern const int x1e = 12;
const int x2 = 2;
extern const int *const pX2 = &x2;
const int x3 = 3;
static const int *const pX3 = &x3;
int main()
{
// make usage of values (to have a side-effect)
std::cout << x1;
std::cout << x1s;
std::cout << x1e;
std::cout << x2;
std::cout << pX2;
std::cout << x3;
std::cout << pX3;
// done
return 0;
}
and the outcome of gcc 8.2
with -O3
:
; int main()
main:
; {
sub rsp, 8
; // make usage of values (to have a side-effect)
; std::cout << x1;
mov esi, 1
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1s;
mov esi, 11
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1e;
mov esi, 12
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x2;
mov esi, 2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX2;
mov esi, OFFSET FLAT:_ZL2x2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; std::cout << x3;
mov esi, 3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX3;
mov esi, OFFSET FLAT:_ZL2x3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; // done
; return 0;
; }
xor eax, eax
add rsp, 8
ret
and the IMHO most interesting part – the global variables:
; const int x3 = 3;
_ZL2x3:
.long 3
; extern const int *const pX2 = &x2;
pX2:
.quad _ZL2x2
; const int x2 = 2;
_ZL2x2:
.long 2
; extern const int x1e = 12;
x1e:
.long 12
x1
,x1s
, andpX3
have been optimized away because they areconst
and not remarked for external linkage.x1e
andpX2
have been allocated because they are remarked for external linkage.x2
has been allocated because it is referred bypX2
which is remarked for external linkage. (Something from extern may accessx2
viapX2
.)x3
was the most tricky one for me.pX3
has been used (instd::cout << pX3;
). Although, its value itself is inlined it refers tox3
. Furthermore, although the access tox3
(instd::cout << x3;
) was inlined as well, the usage of the pointerpX3
initialized with&x3
prevented to optimize this storage away.
Live Demo on godbolt (which has a nice colored dual-view to make it easy to explore)
I did the same with clang 7.0.0
and the outcome was similar.
(I tried it also with msvc v19.15
but I was not able (not patient enough) to evaluate the outcome.)
Concerning 4., I tried additionally:
const int x4 = 4;
static const int *const pX4 = &x4;
and added to main()
:
std::cout << x4;
// No: std::cout << pX4;
In this case, there was no storage allocated – neither for x4
nor for pX4
. (pX4
was optimized away, leaving no “reference” to x4
which in turn was optimized away as well.)
It's amazing...
1
Thanks for your detailed answer. Definitely needed a quick refresher on assembly and registers, once I got that, everything made sense. The example illustrates Peter's answer very clearly imo. With regards to your slight detour though, is const propagation really the reason why C++ allows const as array size but not C? I thought it was because you could usex
fromconst int x
directly as a const since C++ regards it as so, while C does not. See the following for better explanations than mine: stackoverflow.com/questions/25902512
– kop_padawan
Nov 25 '18 at 10:55
@kop_padawan The link you provided does explain this very precisely, I agree. My imagination of "constant" was coined when I was a student and learned Pascal. In Pascal, a constant is nothing addressable and clearly distinguished from a variable. However, this is about C++ and C, so it might be questionable to apply that principles (though I assumed until now that that principle is language agnostic, at least, for imperative languages, but this might be wrong). And, btw. it's decades ago that I was a student... ;-)
– Scheff
Nov 25 '18 at 11:09
@kop_padawan About your concerns regarding "Const propagation" - I'm not quite sure. From the linked Wikipedia article: Constant propagation is the process of substituting the values of known constants in expressions at compile time. I guessed it covers also: The semantic analysis can replace the const variable (e.g. in an array size) by its compile-time computed value to enable proper allocation. May be, I got it wrong and "Const prop." is rather the term exclusively used for optimization phase. I would've enjoyed to discuss (and fix) this but instead I got a downvote without any remark...
– Scheff
Nov 25 '18 at 11:24
The downvote didnt come from me :) I did upvote and accept the answer though. Also not a student despite the username, heh.
– kop_padawan
Nov 25 '18 at 17:01
1
@kop_padawan I didn't think so. Anonymous downvoters don't articulate doubts or critics in comments. ;-) Luckily, there seem to be not so many that it's worth to worry about this...
– Scheff
Nov 25 '18 at 20:17
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%2f53348432%2fwhy-does-a-const-int-not-get-optimized-by-the-compiler-through-the-symbol-table%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
IMHO, Peter provided the explanation in his comment:
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
and this is exactly what I think too.
The const
in C++ is a little bit confusing. It looks like the abbreviation of “constant” but actually it means “read-only”.
This in mind, I never wondered why the following code is legal in C:
enum { N = 3 };
static int a[N]; /* legal in C: N is a constant. */
but this not:
const int n = 3;
static int b[n]; /* illegal in C: n is a read-only variable */
When I switched to C++, I assumed the above for C++ until I realized in a discussion with a colleague that I was wrong. (Not that this broke any written code of mine, but I hate it to be wrong.) ;-)
const int n = 3;
static int b[n]; // legal in C++
and Const propagation is the technique which makes it legal.
However, even with const propagation const int x;
is still a read-only variable which might be addressed.
The OP provided a link about this topic (which might explain it even better than above):
SO: why the size of array as a constant variable is not allowed in C but allowed in C++?
To make this a ful-featured answer I tried to prepare a sample which illustrates the differences:
#include <iostream>
const int x1 = 1;
static const int x1s = 11;
extern const int x1e = 12;
const int x2 = 2;
extern const int *const pX2 = &x2;
const int x3 = 3;
static const int *const pX3 = &x3;
int main()
{
// make usage of values (to have a side-effect)
std::cout << x1;
std::cout << x1s;
std::cout << x1e;
std::cout << x2;
std::cout << pX2;
std::cout << x3;
std::cout << pX3;
// done
return 0;
}
and the outcome of gcc 8.2
with -O3
:
; int main()
main:
; {
sub rsp, 8
; // make usage of values (to have a side-effect)
; std::cout << x1;
mov esi, 1
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1s;
mov esi, 11
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1e;
mov esi, 12
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x2;
mov esi, 2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX2;
mov esi, OFFSET FLAT:_ZL2x2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; std::cout << x3;
mov esi, 3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX3;
mov esi, OFFSET FLAT:_ZL2x3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; // done
; return 0;
; }
xor eax, eax
add rsp, 8
ret
and the IMHO most interesting part – the global variables:
; const int x3 = 3;
_ZL2x3:
.long 3
; extern const int *const pX2 = &x2;
pX2:
.quad _ZL2x2
; const int x2 = 2;
_ZL2x2:
.long 2
; extern const int x1e = 12;
x1e:
.long 12
x1
,x1s
, andpX3
have been optimized away because they areconst
and not remarked for external linkage.x1e
andpX2
have been allocated because they are remarked for external linkage.x2
has been allocated because it is referred bypX2
which is remarked for external linkage. (Something from extern may accessx2
viapX2
.)x3
was the most tricky one for me.pX3
has been used (instd::cout << pX3;
). Although, its value itself is inlined it refers tox3
. Furthermore, although the access tox3
(instd::cout << x3;
) was inlined as well, the usage of the pointerpX3
initialized with&x3
prevented to optimize this storage away.
Live Demo on godbolt (which has a nice colored dual-view to make it easy to explore)
I did the same with clang 7.0.0
and the outcome was similar.
(I tried it also with msvc v19.15
but I was not able (not patient enough) to evaluate the outcome.)
Concerning 4., I tried additionally:
const int x4 = 4;
static const int *const pX4 = &x4;
and added to main()
:
std::cout << x4;
// No: std::cout << pX4;
In this case, there was no storage allocated – neither for x4
nor for pX4
. (pX4
was optimized away, leaving no “reference” to x4
which in turn was optimized away as well.)
It's amazing...
1
Thanks for your detailed answer. Definitely needed a quick refresher on assembly and registers, once I got that, everything made sense. The example illustrates Peter's answer very clearly imo. With regards to your slight detour though, is const propagation really the reason why C++ allows const as array size but not C? I thought it was because you could usex
fromconst int x
directly as a const since C++ regards it as so, while C does not. See the following for better explanations than mine: stackoverflow.com/questions/25902512
– kop_padawan
Nov 25 '18 at 10:55
@kop_padawan The link you provided does explain this very precisely, I agree. My imagination of "constant" was coined when I was a student and learned Pascal. In Pascal, a constant is nothing addressable and clearly distinguished from a variable. However, this is about C++ and C, so it might be questionable to apply that principles (though I assumed until now that that principle is language agnostic, at least, for imperative languages, but this might be wrong). And, btw. it's decades ago that I was a student... ;-)
– Scheff
Nov 25 '18 at 11:09
@kop_padawan About your concerns regarding "Const propagation" - I'm not quite sure. From the linked Wikipedia article: Constant propagation is the process of substituting the values of known constants in expressions at compile time. I guessed it covers also: The semantic analysis can replace the const variable (e.g. in an array size) by its compile-time computed value to enable proper allocation. May be, I got it wrong and "Const prop." is rather the term exclusively used for optimization phase. I would've enjoyed to discuss (and fix) this but instead I got a downvote without any remark...
– Scheff
Nov 25 '18 at 11:24
The downvote didnt come from me :) I did upvote and accept the answer though. Also not a student despite the username, heh.
– kop_padawan
Nov 25 '18 at 17:01
1
@kop_padawan I didn't think so. Anonymous downvoters don't articulate doubts or critics in comments. ;-) Luckily, there seem to be not so many that it's worth to worry about this...
– Scheff
Nov 25 '18 at 20:17
add a comment |
IMHO, Peter provided the explanation in his comment:
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
and this is exactly what I think too.
The const
in C++ is a little bit confusing. It looks like the abbreviation of “constant” but actually it means “read-only”.
This in mind, I never wondered why the following code is legal in C:
enum { N = 3 };
static int a[N]; /* legal in C: N is a constant. */
but this not:
const int n = 3;
static int b[n]; /* illegal in C: n is a read-only variable */
When I switched to C++, I assumed the above for C++ until I realized in a discussion with a colleague that I was wrong. (Not that this broke any written code of mine, but I hate it to be wrong.) ;-)
const int n = 3;
static int b[n]; // legal in C++
and Const propagation is the technique which makes it legal.
However, even with const propagation const int x;
is still a read-only variable which might be addressed.
The OP provided a link about this topic (which might explain it even better than above):
SO: why the size of array as a constant variable is not allowed in C but allowed in C++?
To make this a ful-featured answer I tried to prepare a sample which illustrates the differences:
#include <iostream>
const int x1 = 1;
static const int x1s = 11;
extern const int x1e = 12;
const int x2 = 2;
extern const int *const pX2 = &x2;
const int x3 = 3;
static const int *const pX3 = &x3;
int main()
{
// make usage of values (to have a side-effect)
std::cout << x1;
std::cout << x1s;
std::cout << x1e;
std::cout << x2;
std::cout << pX2;
std::cout << x3;
std::cout << pX3;
// done
return 0;
}
and the outcome of gcc 8.2
with -O3
:
; int main()
main:
; {
sub rsp, 8
; // make usage of values (to have a side-effect)
; std::cout << x1;
mov esi, 1
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1s;
mov esi, 11
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1e;
mov esi, 12
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x2;
mov esi, 2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX2;
mov esi, OFFSET FLAT:_ZL2x2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; std::cout << x3;
mov esi, 3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX3;
mov esi, OFFSET FLAT:_ZL2x3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; // done
; return 0;
; }
xor eax, eax
add rsp, 8
ret
and the IMHO most interesting part – the global variables:
; const int x3 = 3;
_ZL2x3:
.long 3
; extern const int *const pX2 = &x2;
pX2:
.quad _ZL2x2
; const int x2 = 2;
_ZL2x2:
.long 2
; extern const int x1e = 12;
x1e:
.long 12
x1
,x1s
, andpX3
have been optimized away because they areconst
and not remarked for external linkage.x1e
andpX2
have been allocated because they are remarked for external linkage.x2
has been allocated because it is referred bypX2
which is remarked for external linkage. (Something from extern may accessx2
viapX2
.)x3
was the most tricky one for me.pX3
has been used (instd::cout << pX3;
). Although, its value itself is inlined it refers tox3
. Furthermore, although the access tox3
(instd::cout << x3;
) was inlined as well, the usage of the pointerpX3
initialized with&x3
prevented to optimize this storage away.
Live Demo on godbolt (which has a nice colored dual-view to make it easy to explore)
I did the same with clang 7.0.0
and the outcome was similar.
(I tried it also with msvc v19.15
but I was not able (not patient enough) to evaluate the outcome.)
Concerning 4., I tried additionally:
const int x4 = 4;
static const int *const pX4 = &x4;
and added to main()
:
std::cout << x4;
// No: std::cout << pX4;
In this case, there was no storage allocated – neither for x4
nor for pX4
. (pX4
was optimized away, leaving no “reference” to x4
which in turn was optimized away as well.)
It's amazing...
1
Thanks for your detailed answer. Definitely needed a quick refresher on assembly and registers, once I got that, everything made sense. The example illustrates Peter's answer very clearly imo. With regards to your slight detour though, is const propagation really the reason why C++ allows const as array size but not C? I thought it was because you could usex
fromconst int x
directly as a const since C++ regards it as so, while C does not. See the following for better explanations than mine: stackoverflow.com/questions/25902512
– kop_padawan
Nov 25 '18 at 10:55
@kop_padawan The link you provided does explain this very precisely, I agree. My imagination of "constant" was coined when I was a student and learned Pascal. In Pascal, a constant is nothing addressable and clearly distinguished from a variable. However, this is about C++ and C, so it might be questionable to apply that principles (though I assumed until now that that principle is language agnostic, at least, for imperative languages, but this might be wrong). And, btw. it's decades ago that I was a student... ;-)
– Scheff
Nov 25 '18 at 11:09
@kop_padawan About your concerns regarding "Const propagation" - I'm not quite sure. From the linked Wikipedia article: Constant propagation is the process of substituting the values of known constants in expressions at compile time. I guessed it covers also: The semantic analysis can replace the const variable (e.g. in an array size) by its compile-time computed value to enable proper allocation. May be, I got it wrong and "Const prop." is rather the term exclusively used for optimization phase. I would've enjoyed to discuss (and fix) this but instead I got a downvote without any remark...
– Scheff
Nov 25 '18 at 11:24
The downvote didnt come from me :) I did upvote and accept the answer though. Also not a student despite the username, heh.
– kop_padawan
Nov 25 '18 at 17:01
1
@kop_padawan I didn't think so. Anonymous downvoters don't articulate doubts or critics in comments. ;-) Luckily, there seem to be not so many that it's worth to worry about this...
– Scheff
Nov 25 '18 at 20:17
add a comment |
IMHO, Peter provided the explanation in his comment:
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
and this is exactly what I think too.
The const
in C++ is a little bit confusing. It looks like the abbreviation of “constant” but actually it means “read-only”.
This in mind, I never wondered why the following code is legal in C:
enum { N = 3 };
static int a[N]; /* legal in C: N is a constant. */
but this not:
const int n = 3;
static int b[n]; /* illegal in C: n is a read-only variable */
When I switched to C++, I assumed the above for C++ until I realized in a discussion with a colleague that I was wrong. (Not that this broke any written code of mine, but I hate it to be wrong.) ;-)
const int n = 3;
static int b[n]; // legal in C++
and Const propagation is the technique which makes it legal.
However, even with const propagation const int x;
is still a read-only variable which might be addressed.
The OP provided a link about this topic (which might explain it even better than above):
SO: why the size of array as a constant variable is not allowed in C but allowed in C++?
To make this a ful-featured answer I tried to prepare a sample which illustrates the differences:
#include <iostream>
const int x1 = 1;
static const int x1s = 11;
extern const int x1e = 12;
const int x2 = 2;
extern const int *const pX2 = &x2;
const int x3 = 3;
static const int *const pX3 = &x3;
int main()
{
// make usage of values (to have a side-effect)
std::cout << x1;
std::cout << x1s;
std::cout << x1e;
std::cout << x2;
std::cout << pX2;
std::cout << x3;
std::cout << pX3;
// done
return 0;
}
and the outcome of gcc 8.2
with -O3
:
; int main()
main:
; {
sub rsp, 8
; // make usage of values (to have a side-effect)
; std::cout << x1;
mov esi, 1
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1s;
mov esi, 11
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1e;
mov esi, 12
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x2;
mov esi, 2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX2;
mov esi, OFFSET FLAT:_ZL2x2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; std::cout << x3;
mov esi, 3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX3;
mov esi, OFFSET FLAT:_ZL2x3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; // done
; return 0;
; }
xor eax, eax
add rsp, 8
ret
and the IMHO most interesting part – the global variables:
; const int x3 = 3;
_ZL2x3:
.long 3
; extern const int *const pX2 = &x2;
pX2:
.quad _ZL2x2
; const int x2 = 2;
_ZL2x2:
.long 2
; extern const int x1e = 12;
x1e:
.long 12
x1
,x1s
, andpX3
have been optimized away because they areconst
and not remarked for external linkage.x1e
andpX2
have been allocated because they are remarked for external linkage.x2
has been allocated because it is referred bypX2
which is remarked for external linkage. (Something from extern may accessx2
viapX2
.)x3
was the most tricky one for me.pX3
has been used (instd::cout << pX3;
). Although, its value itself is inlined it refers tox3
. Furthermore, although the access tox3
(instd::cout << x3;
) was inlined as well, the usage of the pointerpX3
initialized with&x3
prevented to optimize this storage away.
Live Demo on godbolt (which has a nice colored dual-view to make it easy to explore)
I did the same with clang 7.0.0
and the outcome was similar.
(I tried it also with msvc v19.15
but I was not able (not patient enough) to evaluate the outcome.)
Concerning 4., I tried additionally:
const int x4 = 4;
static const int *const pX4 = &x4;
and added to main()
:
std::cout << x4;
// No: std::cout << pX4;
In this case, there was no storage allocated – neither for x4
nor for pX4
. (pX4
was optimized away, leaving no “reference” to x4
which in turn was optimized away as well.)
It's amazing...
IMHO, Peter provided the explanation in his comment:
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
and this is exactly what I think too.
The const
in C++ is a little bit confusing. It looks like the abbreviation of “constant” but actually it means “read-only”.
This in mind, I never wondered why the following code is legal in C:
enum { N = 3 };
static int a[N]; /* legal in C: N is a constant. */
but this not:
const int n = 3;
static int b[n]; /* illegal in C: n is a read-only variable */
When I switched to C++, I assumed the above for C++ until I realized in a discussion with a colleague that I was wrong. (Not that this broke any written code of mine, but I hate it to be wrong.) ;-)
const int n = 3;
static int b[n]; // legal in C++
and Const propagation is the technique which makes it legal.
However, even with const propagation const int x;
is still a read-only variable which might be addressed.
The OP provided a link about this topic (which might explain it even better than above):
SO: why the size of array as a constant variable is not allowed in C but allowed in C++?
To make this a ful-featured answer I tried to prepare a sample which illustrates the differences:
#include <iostream>
const int x1 = 1;
static const int x1s = 11;
extern const int x1e = 12;
const int x2 = 2;
extern const int *const pX2 = &x2;
const int x3 = 3;
static const int *const pX3 = &x3;
int main()
{
// make usage of values (to have a side-effect)
std::cout << x1;
std::cout << x1s;
std::cout << x1e;
std::cout << x2;
std::cout << pX2;
std::cout << x3;
std::cout << pX3;
// done
return 0;
}
and the outcome of gcc 8.2
with -O3
:
; int main()
main:
; {
sub rsp, 8
; // make usage of values (to have a side-effect)
; std::cout << x1;
mov esi, 1
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1s;
mov esi, 11
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x1e;
mov esi, 12
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << x2;
mov esi, 2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX2;
mov esi, OFFSET FLAT:_ZL2x2
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; std::cout << x3;
mov esi, 3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSolsEi
; std::cout << pX3;
mov esi, OFFSET FLAT:_ZL2x3
mov edi, OFFSET FLAT:_ZSt4cout
call _ZNSo9_M_insertIPKvEERSoT_
; // done
; return 0;
; }
xor eax, eax
add rsp, 8
ret
and the IMHO most interesting part – the global variables:
; const int x3 = 3;
_ZL2x3:
.long 3
; extern const int *const pX2 = &x2;
pX2:
.quad _ZL2x2
; const int x2 = 2;
_ZL2x2:
.long 2
; extern const int x1e = 12;
x1e:
.long 12
x1
,x1s
, andpX3
have been optimized away because they areconst
and not remarked for external linkage.x1e
andpX2
have been allocated because they are remarked for external linkage.x2
has been allocated because it is referred bypX2
which is remarked for external linkage. (Something from extern may accessx2
viapX2
.)x3
was the most tricky one for me.pX3
has been used (instd::cout << pX3;
). Although, its value itself is inlined it refers tox3
. Furthermore, although the access tox3
(instd::cout << x3;
) was inlined as well, the usage of the pointerpX3
initialized with&x3
prevented to optimize this storage away.
Live Demo on godbolt (which has a nice colored dual-view to make it easy to explore)
I did the same with clang 7.0.0
and the outcome was similar.
(I tried it also with msvc v19.15
but I was not able (not patient enough) to evaluate the outcome.)
Concerning 4., I tried additionally:
const int x4 = 4;
static const int *const pX4 = &x4;
and added to main()
:
std::cout << x4;
// No: std::cout << pX4;
In this case, there was no storage allocated – neither for x4
nor for pX4
. (pX4
was optimized away, leaving no “reference” to x4
which in turn was optimized away as well.)
It's amazing...
edited Nov 25 '18 at 11:14
answered Nov 17 '18 at 9:36
ScheffScheff
7,79521325
7,79521325
1
Thanks for your detailed answer. Definitely needed a quick refresher on assembly and registers, once I got that, everything made sense. The example illustrates Peter's answer very clearly imo. With regards to your slight detour though, is const propagation really the reason why C++ allows const as array size but not C? I thought it was because you could usex
fromconst int x
directly as a const since C++ regards it as so, while C does not. See the following for better explanations than mine: stackoverflow.com/questions/25902512
– kop_padawan
Nov 25 '18 at 10:55
@kop_padawan The link you provided does explain this very precisely, I agree. My imagination of "constant" was coined when I was a student and learned Pascal. In Pascal, a constant is nothing addressable and clearly distinguished from a variable. However, this is about C++ and C, so it might be questionable to apply that principles (though I assumed until now that that principle is language agnostic, at least, for imperative languages, but this might be wrong). And, btw. it's decades ago that I was a student... ;-)
– Scheff
Nov 25 '18 at 11:09
@kop_padawan About your concerns regarding "Const propagation" - I'm not quite sure. From the linked Wikipedia article: Constant propagation is the process of substituting the values of known constants in expressions at compile time. I guessed it covers also: The semantic analysis can replace the const variable (e.g. in an array size) by its compile-time computed value to enable proper allocation. May be, I got it wrong and "Const prop." is rather the term exclusively used for optimization phase. I would've enjoyed to discuss (and fix) this but instead I got a downvote without any remark...
– Scheff
Nov 25 '18 at 11:24
The downvote didnt come from me :) I did upvote and accept the answer though. Also not a student despite the username, heh.
– kop_padawan
Nov 25 '18 at 17:01
1
@kop_padawan I didn't think so. Anonymous downvoters don't articulate doubts or critics in comments. ;-) Luckily, there seem to be not so many that it's worth to worry about this...
– Scheff
Nov 25 '18 at 20:17
add a comment |
1
Thanks for your detailed answer. Definitely needed a quick refresher on assembly and registers, once I got that, everything made sense. The example illustrates Peter's answer very clearly imo. With regards to your slight detour though, is const propagation really the reason why C++ allows const as array size but not C? I thought it was because you could usex
fromconst int x
directly as a const since C++ regards it as so, while C does not. See the following for better explanations than mine: stackoverflow.com/questions/25902512
– kop_padawan
Nov 25 '18 at 10:55
@kop_padawan The link you provided does explain this very precisely, I agree. My imagination of "constant" was coined when I was a student and learned Pascal. In Pascal, a constant is nothing addressable and clearly distinguished from a variable. However, this is about C++ and C, so it might be questionable to apply that principles (though I assumed until now that that principle is language agnostic, at least, for imperative languages, but this might be wrong). And, btw. it's decades ago that I was a student... ;-)
– Scheff
Nov 25 '18 at 11:09
@kop_padawan About your concerns regarding "Const propagation" - I'm not quite sure. From the linked Wikipedia article: Constant propagation is the process of substituting the values of known constants in expressions at compile time. I guessed it covers also: The semantic analysis can replace the const variable (e.g. in an array size) by its compile-time computed value to enable proper allocation. May be, I got it wrong and "Const prop." is rather the term exclusively used for optimization phase. I would've enjoyed to discuss (and fix) this but instead I got a downvote without any remark...
– Scheff
Nov 25 '18 at 11:24
The downvote didnt come from me :) I did upvote and accept the answer though. Also not a student despite the username, heh.
– kop_padawan
Nov 25 '18 at 17:01
1
@kop_padawan I didn't think so. Anonymous downvoters don't articulate doubts or critics in comments. ;-) Luckily, there seem to be not so many that it's worth to worry about this...
– Scheff
Nov 25 '18 at 20:17
1
1
Thanks for your detailed answer. Definitely needed a quick refresher on assembly and registers, once I got that, everything made sense. The example illustrates Peter's answer very clearly imo. With regards to your slight detour though, is const propagation really the reason why C++ allows const as array size but not C? I thought it was because you could use
x
from const int x
directly as a const since C++ regards it as so, while C does not. See the following for better explanations than mine: stackoverflow.com/questions/25902512– kop_padawan
Nov 25 '18 at 10:55
Thanks for your detailed answer. Definitely needed a quick refresher on assembly and registers, once I got that, everything made sense. The example illustrates Peter's answer very clearly imo. With regards to your slight detour though, is const propagation really the reason why C++ allows const as array size but not C? I thought it was because you could use
x
from const int x
directly as a const since C++ regards it as so, while C does not. See the following for better explanations than mine: stackoverflow.com/questions/25902512– kop_padawan
Nov 25 '18 at 10:55
@kop_padawan The link you provided does explain this very precisely, I agree. My imagination of "constant" was coined when I was a student and learned Pascal. In Pascal, a constant is nothing addressable and clearly distinguished from a variable. However, this is about C++ and C, so it might be questionable to apply that principles (though I assumed until now that that principle is language agnostic, at least, for imperative languages, but this might be wrong). And, btw. it's decades ago that I was a student... ;-)
– Scheff
Nov 25 '18 at 11:09
@kop_padawan The link you provided does explain this very precisely, I agree. My imagination of "constant" was coined when I was a student and learned Pascal. In Pascal, a constant is nothing addressable and clearly distinguished from a variable. However, this is about C++ and C, so it might be questionable to apply that principles (though I assumed until now that that principle is language agnostic, at least, for imperative languages, but this might be wrong). And, btw. it's decades ago that I was a student... ;-)
– Scheff
Nov 25 '18 at 11:09
@kop_padawan About your concerns regarding "Const propagation" - I'm not quite sure. From the linked Wikipedia article: Constant propagation is the process of substituting the values of known constants in expressions at compile time. I guessed it covers also: The semantic analysis can replace the const variable (e.g. in an array size) by its compile-time computed value to enable proper allocation. May be, I got it wrong and "Const prop." is rather the term exclusively used for optimization phase. I would've enjoyed to discuss (and fix) this but instead I got a downvote without any remark...
– Scheff
Nov 25 '18 at 11:24
@kop_padawan About your concerns regarding "Const propagation" - I'm not quite sure. From the linked Wikipedia article: Constant propagation is the process of substituting the values of known constants in expressions at compile time. I guessed it covers also: The semantic analysis can replace the const variable (e.g. in an array size) by its compile-time computed value to enable proper allocation. May be, I got it wrong and "Const prop." is rather the term exclusively used for optimization phase. I would've enjoyed to discuss (and fix) this but instead I got a downvote without any remark...
– Scheff
Nov 25 '18 at 11:24
The downvote didnt come from me :) I did upvote and accept the answer though. Also not a student despite the username, heh.
– kop_padawan
Nov 25 '18 at 17:01
The downvote didnt come from me :) I did upvote and accept the answer though. Also not a student despite the username, heh.
– kop_padawan
Nov 25 '18 at 17:01
1
1
@kop_padawan I didn't think so. Anonymous downvoters don't articulate doubts or critics in comments. ;-) Luckily, there seem to be not so many that it's worth to worry about this...
– Scheff
Nov 25 '18 at 20:17
@kop_padawan I didn't think so. Anonymous downvoters don't articulate doubts or critics in comments. ;-) Luckily, there seem to be not so many that it's worth to worry about this...
– Scheff
Nov 25 '18 at 20:17
add a comment |
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%2f53348432%2fwhy-does-a-const-int-not-get-optimized-by-the-compiler-through-the-symbol-table%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
The "compiler" seems to be an important part in this.
– Ted Lyngmo
Nov 17 '18 at 5:12
1
But how do you use
y
? Otherwise the compiler could optimize away both? And depending on how you usey
then it might be able to do it anyway.– Some programmer dude
Nov 17 '18 at 5:17
1
Edited the title to include compiler
– kop_padawan
Nov 17 '18 at 5:22
3
If a pointer is initialised to contain the address of a variable, and that pointer can be accessed from another compilation unit, then it would be reasonable for the compiler to allow for the possibility that the pointer IS dereferenced after being initialised in some compilation unit that is not visible to the compiler. One consequence of that is not optimising the pointer or the variable out of existence. There are numerous other reasoning approaches that might lead to the same outcome, depending on what code the compiler can actually see.
– Peter
Nov 17 '18 at 7:18