Why does a const int not get optimized by the compiler (through the symbol table) if another pointer points...












1















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?










share|improve this question

























  • 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 use y 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
















1















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?










share|improve this question

























  • 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 use y 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














1












1








1


0






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?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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





    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






  • 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








  • 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












1 Answer
1






active

oldest

votes


















2














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



  1. x1, x1s, and pX3 have been optimized away because they are const and not remarked for external linkage.


  2. x1e and pX2 have been allocated because they are remarked for external linkage.


  3. x2 has been allocated because it is referred by pX2 which is remarked for external linkage. (Something from extern may access x2 via pX2.)


  4. x3 was the most tricky one for me. pX3 has been used (in std::cout << pX3;). Although, its value itself is inlined it refers to x3. Furthermore, although the access to x3 (in std::cout << x3;) was inlined as well, the usage of the pointer pX3 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...






share|improve this answer





















  • 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













  • @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











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
});


}
});














draft saved

draft discarded


















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









2














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



  1. x1, x1s, and pX3 have been optimized away because they are const and not remarked for external linkage.


  2. x1e and pX2 have been allocated because they are remarked for external linkage.


  3. x2 has been allocated because it is referred by pX2 which is remarked for external linkage. (Something from extern may access x2 via pX2.)


  4. x3 was the most tricky one for me. pX3 has been used (in std::cout << pX3;). Although, its value itself is inlined it refers to x3. Furthermore, although the access to x3 (in std::cout << x3;) was inlined as well, the usage of the pointer pX3 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...






share|improve this answer





















  • 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













  • @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
















2














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



  1. x1, x1s, and pX3 have been optimized away because they are const and not remarked for external linkage.


  2. x1e and pX2 have been allocated because they are remarked for external linkage.


  3. x2 has been allocated because it is referred by pX2 which is remarked for external linkage. (Something from extern may access x2 via pX2.)


  4. x3 was the most tricky one for me. pX3 has been used (in std::cout << pX3;). Although, its value itself is inlined it refers to x3. Furthermore, although the access to x3 (in std::cout << x3;) was inlined as well, the usage of the pointer pX3 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...






share|improve this answer





















  • 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













  • @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














2












2








2







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



  1. x1, x1s, and pX3 have been optimized away because they are const and not remarked for external linkage.


  2. x1e and pX2 have been allocated because they are remarked for external linkage.


  3. x2 has been allocated because it is referred by pX2 which is remarked for external linkage. (Something from extern may access x2 via pX2.)


  4. x3 was the most tricky one for me. pX3 has been used (in std::cout << pX3;). Although, its value itself is inlined it refers to x3. Furthermore, although the access to x3 (in std::cout << x3;) was inlined as well, the usage of the pointer pX3 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...






share|improve this answer















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



  1. x1, x1s, and pX3 have been optimized away because they are const and not remarked for external linkage.


  2. x1e and pX2 have been allocated because they are remarked for external linkage.


  3. x2 has been allocated because it is referred by pX2 which is remarked for external linkage. (Something from extern may access x2 via pX2.)


  4. x3 was the most tricky one for me. pX3 has been used (in std::cout << pX3;). Although, its value itself is inlined it refers to x3. Furthermore, although the access to x3 (in std::cout << x3;) was inlined as well, the usage of the pointer pX3 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...







share|improve this answer














share|improve this answer



share|improve this answer








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 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 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





    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 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







這個網誌中的熱門文章

Xamarin.form Move up view when keyboard appear

Post-Redirect-Get with Spring WebFlux and Thymeleaf

Anylogic : not able to use stopDelay()