How does C++ keep the const value? [duplicate] - c++

This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
#include <iostream>
using namespace std;
int main() {
const int a = 10;
auto *b = const_cast<int *>(&a);
*b = 20;
cout << a << " " << *b;
cout << endl << &a << " " << b;
}
The output looks like:
10 20
0x7ffeeb1d396c 0x7ffeeb1d396c
The a and *b are at the same address, why do they have different value?

Most probably this is caused by optimization.
As molbdnilo already said in his comment: "Compilers trust you blindly. If you lie to them, strange things can happen."
So when optimization is enabled, the compiler finds the declaration
const int a = 10;
and thinks "ah, this will never change, so we don't need a "real" variable and can replace all appearances of a in the code simply with 10". This behavior is called constant folding.
Now in the next line you "cheat" the compiler:
auto *b = const_cast<int *>(&a);
*b = 20;
and change a, although you have promised not to do so.
The result is confusion.
Like a lot of people have already mentioned and Christian Hackl has thoroughly analyzed in his excellent in-depth answer, it's undefined behavior. The compiler is generally allowed to apply constant folding on constants, which are explicitly declared const.
Your question is a very good example (I don't know how anyone can vote it down!) why const_cast is very dangerous (and even more when combined with raw pointers), should be only used if absolutely necessary, and should be at least thoroughly commented why it was used if it was unavoidable. Comments are important in that case because it's not only the compiler you are "cheating":
Also your co-workers will rely on the information const and rely on the information that it won't change. If it DOES change though, and you didn't inform them, and did not comment, and did not exactly know what you were doing, you'll have a bad day at work :)
Try it out: Perhaps your program will even behave different in debug build (not optimized) and release build (optimized), and those bugs are usually pretty annoying to fix.

I think it helps to view const like this:
If you declare something as const it is actually not the compiler that ensures that you dont change it, but rather the opposite: you make a promise to the compiler that you wont change it.
The language helps you a bit to keep your promise, eg you cannot do:
const int a = 5;
a = 6; // error
but as you discovered, you indeed can attempt to modify something that you declared const. However, then you broke your promise and as always in c++, once you break the rules you are on your own (aka undefined behaviour).

The a and *b are at the same address, why do they have different
value?
They don't, not according to C++. Neither do they, according to C++.
How can that be? The answer is that the C++ language does not define the behaviour of your program because you modify a const object. That's not allowed, and there are no rules for what will happen in such a case.
You are only allowed to use const_cast in order to modify something which wasn't const in the first place:
int a = 123;
int const* ptr1 = &a;
// *ptr1 = 456; // compilation error
int* ptr2 = const_cast<int*>(ptr1);
*ptr2 = 456; // OK
So you've ended up with a program whose behaviour is not defined by C++. The behaviour is instead defined by compiler writers, compiler settings and pure chance.
That's also what's wrong with your question. It's impossible to give you a correct answer without knowing exactly how you compiled this and on which system it runs, and perhaps even then there are random factors involved.
You can inspect your binary to find out what the compiler thought it was doing; there are even online tools like https://gcc.godbolt.org/ for that. But try to use printf instead of std::cout for such an analysis; it will produce easier-to-read assembly code. You may also use easier-to-spot numbers, like 123 and 456.
For example, assuming that you even use GCC, compare these two programs; the only difference is the const modifier for a:
#include <stdio.h>
int main() {
int const a = 123;
auto *b = const_cast<int *>(&a);
*b = 456;
printf("%d", a);
printf("%d", *b);
}
#include <stdio.h>
int main() {
int a = 123;
auto *b = const_cast<int *>(&a);
*b = 456;
printf("%d", a);
printf("%d", *b);
}
Look at what the printf("%d", a); call becomes. In the const version, it becomes:
mov esi, 123
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
In the non-const version:
mov eax, DWORD PTR [rbp-12]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
Without going too much into the details of assembly code, one can see that the compiler optimised the const variable such that the value 123 is pushed directly to printf. It doesn't really treat a as a variable for the printf call, but it does do so for the pointer initialisation.
Such chaos is the nature of undefined behaviour. The moral of the story is that you should always avoid undefined behaviour, and thinking twice before casting is an important part of allowing the compiler to help you in that endeavor.

Compiling your code once with const and once without const using gcc, shows that there either no space is allocated for a, or it's content is being ignored in const version. (even with 0 optimization) The only difference in their assembly result is the line which you print the a. Compiler simply prints 10 instead of refering to memory and fetching contents of a: (left side is const int a and right side is int a version)
movl $10, %esi | movl -36(%rbp), %eax
> movl %eax, %esi
As you can see there is an extra memory access for non-const version, which we know is expensive in terms of time. So the compiler decided to trust your code, and concluded that a const is never to be changed, and replaced its value wherever the variable is referenced.
Compiler options: --std=c++11 -O0 -S

Related

Why does this bad universal initializer syntax compile and result in unpredictable behavior?

I have a bunch of code for working with hardware (FPGA) registers, which is roughly of the form:
struct SomeRegFields {
unsigned int lower : 16;
unsigned int upper : 16;
};
union SomeReg {
uint32_t wholeReg;
SomeRegFields fields;
};
(Most of these register types are more complex. This is illustrative.)
While cleaning up a bunch of code that set up registers in the following way:
SomeReg reg1;
reg1.wholeReg = 0;
// ... assign individual fields
card->writeReg(REG1_ADDRESS, reg1.wholeReg);
SomeReg reg2;
reg2.wholeReg = card->readReg(REG2_ADDRESS);
// ... do something with reg2 field values
I got a bit absent-minded and accidentally ended up with the following:
SomeReg reg1{ reg1.wholeReg = 0 };
SomeReg reg2{ reg2.wholeReg = card->readReg(REG2_ADDRESS) };
The reg1.wholeReg = part is wrong, of course, and should be removed.
What's bugging me is that this compiles on both MSVC and GCC. I would have expected a syntax error here. Moreover, sometimes it works fine and the value actually gets copied/assigned correctly, but other times, it will result in a 0 value even if the register value returned is non-0. It's unpredictable, but appears to be consistent between runs which cases work and which don't.
Any idea why the compilers don't flag this as bad syntax, and why it seems to work in some cases but breaks in others? I assume this is undefined behavior, of course, but why would it would change behaviors between what often seem like nearly identical calls, often back-to-back?
Some compilation info:
If I run this through Compiler Explorer:
int main()
{
SomeReg myReg { myReg.wholeReg = 10 };
return myReg.fields.upper;
}
This is the code GCC trunk spits out for main with optimization off (-O0):
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 10
* mov eax, DWORD PTR [rbp-4]
* mov DWORD PTR [rbp-4], eax
movzx eax, WORD PTR [rbp-2]
movzx eax, ax
pop rbp
ret
The lines marked with * are the only difference between this version and a version without the bad myReg.wholeReg = part. MSVC gives similar results, though even with optimization off, it seems to be doing some. In this case, it just causes an extra assignment in and back out of a register, so it still works as intended, but given my accidental experimental results, it must not always compile this way in more complex cases, i.e. not assigning from a compile-time-deducible value.
reg1.wholeReg = card->readReg(REG2_ADDRESS)
This is simply treated as an expression. You are assigning the return value of card->readReg(REG2_ADDRESS) to reg1.wholeReg and then you use the result of this expression (a lvalue referring to reg1.wholeReg) to aggregate-initialize the first member of reg2 (i.e. reg2.wholeReg). Afterwards reg1 and reg2 should hold the same value, the return value of the function.
Syntactically the same happens in
SomeReg reg1{ reg1.wholeReg = 0 };
However, here it is technically undefined behavior since you are not allowed to access variables or class members before they are initialized. Practically speaking, I would expect this to usually work nontheless, initializing reg1.wholeReg to 0 and then once again.
Referring to a variable in its own initializer is syntactically correct and may sometimes be useful (e.g. to pass a pointer to the variable itself). This is why there is no compilation error.
int main()
{
SomeReg myReg { myReg.wholeReg = 10 };
return myReg.fields.upper;
}
This has additional undefined behavior, even if you fix the initialization, because you can't use a union in C++ for type punning at all. That is always undefined behavior, although some compilers might allow it to the degree that is allowed in C. Still, the standard does not allow reading fields.upper if wholeReg is the active member of the union (meaning the last member to which a value was assigned).

Why don't GCC & MSVC optimize based on uninitialized variables? Can I force them to?

Consider some dead-simple code (or a more complicated one, see below1) that uses an uninitialized stack variable, e.g.:
int main() { int x; return 17 / x; }
Here's what GCC emits (-O3):
mov eax, 17
xor ecx, ecx
cdq
idiv ecx
ret
Here's what MSVC emits (-O2):
mov eax, 17
cdq
idiv DWORD PTR [rsp]
ret 0
For reference, here's what Clang emits (-O3):
ret
The thing is, all three compilers detect that this is an uninitialized variable just fine (-Wall), but only one of them actually performs any optimizations based on it.
This is kind of stumping me... I thought all the decades of fighting over undefined behavior was to allow compiler optimizations, and yet I'm seeing only one compiler cares to optimize even the most basic cases of UB.
Why is this? What do I do if I want compilers other than Clang to optimize such cases of UB? Is there any way for me to actually get the benefits of UB instead of just the downsides with either compiler?
Footnotes
1 Apparently this was too much of an SSCCE for some folks to appreciate the actual issue. If you want a more complicated example of this problem that isn't undefined on every execution of the program, just massage it a bit. e.g.:
int main(int argc, char *[])
{
int x;
if (argc) { x = 100 + (argc * argc + x); }
return x;
}
On GCC you get:
main:
xor eax, eax
test edi, edi
je .L1
imul edi, edi
lea eax, [rdi+100]
.L1:
ret
On Clang you get:
main:
ret
Same issue, just more complicated.
Optimizing for actually reading unintiailized data is not the point.
Optimizing for assuming the data you read must have been initialized is.
So if you have some variable that can only be written to as 3 or 1, the compiler can assume it is odd.
Or, if you add positive signed constant to a signed value, we can assume the result is larger than the original signed value (this makes some loops faster).
What the optimizer does when it proves an uninitialized value is read isn't important; making UB or indeterminate value calculation faster is not the point. Well behaved programs don't do that on purpose, spending effort making it faster (or slower, or caring) is a waste of compiler writers time.
It may fall out of other efforts. Or it may not.
Consider this example:
int foo(bool x) {
int y;
if (x) y = 3;
return y;
}
Gcc realizes that the only way the function can return something well defined is when x is true. Hence, when optimizations are turned on there is no brach:
foo(bool):
mov eax, 3
ret
Calling foo(true) is not undefined behavior. Calling foo(false) is undefined behavior. There is nothing in the standard that specifies why foo(false) returns 3. There is also nothing in the standard that mandates that foo(false) does not return 3. Compilers do not optimize code that has undefined behavior, but compilers can optimize code without UB (eg remove the branch in foo) because it is not specified what happens when there is UB.
What do I do if I want compilers other than Clang to optimize such cases of UB?
Compilers do that by default. Gcc is not different than Clang with respect to that.
In your example of
int main() { int x; return 17 / x; }
there is no missed optimization, because it is not defined what the code will do in the first place.
Your second example can be considered as a missed opportunity for optimization. Though, again: UB grants opportunities to optimize code that does not have UB. The idea is not that you introduce UB in your code to gain optimizations. As your second example can (and should be) rewritten as
int main(int argc, char *[])
{
int x = 100 + (argc * argc + x);
return x;
}
It isnt a big issue in practice that gcc doesn't bother to remove the branch in your version. If you don't need the branch you don't have to write it just to expect the compiler to remove it.
The Standard uses the term "Undefined Behavior" to refer to actions which in some contexts might be non-portable but correct, but in other contexts would be erroneous, without making any effort to distinguish into when a particular action should be viewed one way or the other.
In C89 and C99, if it would be possible for a type's underlying storage to hold an invalid bit pattern, attempting to use an uninitialized automatic-duration or malloc-allocated object of that type would invoke Undefined Behavior, but if all possible bit patterns would be valid, accessing such an object would simply yield an Unspecified Value of that type. This meant, for example, that a program could do something like:
struct ushorts256 { uint16_t dat[256]; } x,y;
void test(void)
{
struct ushorts256 temp;
int i;
for (i=0; i<86; i++)
temp.dat[i*3]=i;
x=temp;
y=temp;
}
and if the callers only cared about what was in multiple-of-3 elements of the structures, there would be no need to have the code worry about the other 171 values of temp.
C11 changed the rules so that compiler writers wouldn't have to follow the C89 and C99 behavior if they felt there was something more useful they could do. For example, depending upon what calling code would do with the arrays, it might be more efficient to simply have the code write every third item of x and every third item of y, leaving the remaining items alone. A consequence of this would be that non-multiple-of-3 items of x might not match the corresponding items of y, but people seeking to sell compilers were expected to be able to judge their particular customers' needs better than the Committee ever could.
Some compilers treat uninitialized objects in a manner consistent with C89 and C99. Some may exploit the freedom to have the values behave non-deterministically (as in the example above) but without not disrupting program behavior. Some may opt to treat any programs that access uninitialized variables in gratuitously meaningless fashion. Portable programs may not rely upon any particular treatment, but the authors of the Standard have expressly stated they did not wish to "demean" useful programs that happened to be non-portable (see http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf page 13).

const vs non-const variable with no change in value once assign

In C++, if value of a variable never gets changed once assigned in whole program VS If making that variable as const , In which case executable code is faster?
How compiler optimize executable code in case 1?
A clever compiler can understand that the value of a variable is never changed, thus optimizing the related code, even without the explicit const keyword by the programmer.
As for your second, question, when you mark a variable as const, then the follow might happen: the "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". Read more in What kind of optimization does const offer in C/C++? (if any).
I said might, because const does not mean that this is a constant expression for sure, which can be done by using constexpr instead, as I explain bellow.
In general, you should think about safer code, rather than faster code when it comes to using the const keyword. So unless, you do it for safer and more readable code, then you are likely a victim of premature optimization.
Bonus:
C++ offers the constexpr keyword, which allows the programmer to mark a variable as what the Standard calls constant expressions. A constant expression is more than merely constant.
Read more in Difference between `constexpr` and `const` and When should you use constexpr capability in C++11?
PS: Constness prevents moving, so using const too liberally may turn your code to execute slower.
In which case executable code is faster?
The code is faster in case on using const, because compiler has more room for optimization. Consider this snippet:
int c = 5;
[...]
int x = c + 5;
If c is constant, it will simply assign 10 to x. If c is not a constant, it depend on compiler if it will be able to deduct from the code that c is de-facto constant.
How compiler optimize executable code in case 1?
Compiler has harder time to optimize the code in case the variable is not constant. The broader the scope of the variable, the harder for the compiler to make sure the variable is not changing.
For simple cases, like a local variables, the compiler with basic optimizations will be able to deduct that the variable is a constant. So it will treat it like a constant.
if (...) {
int c = 5;
[...]
int x = c + 5;
}
For broader scopes, like global variables, external variables etc., if the compiler is not able to analyze the whole scope, it will treat it like a normal variable, i.e. allocate some space, generate load and store operations etc.
file1.c
int c = 5;
file2.c
extern int c;
[...]
int x = c + 5;
There are more aggressive optimization options, like link time optimizations, which might help in such cases. But still, performance-wise, the const keyword helps, especially for variables with wide scopes.
EDIT:
Simple example
File const.C:
const int c = 5;
volatile int x;
int main(int argc, char **argv)
{
x = c + 5;
}
Compilation:
$ g++ const.C -O3 -g
Disassembly:
5 {
6 x = c + 5;
0x00000000004003e0 <+0>: movl $0xa,0x200c4a(%rip) # 0x601034 <x>
7 }
So we just move 10 (0xa) to x.
File nonconst.C:
int c = 5;
volatile int x;
int main(int argc, char **argv)
{
x = c + 5;
}
Compilation:
$ g++ nonconst.C -O3 -g
Disassembly:
5 {
6 x = c + 5;
0x00000000004003e0 <+0>: mov 0x200c4a(%rip),%eax # 0x601030 <c>
0x00000000004003e6 <+6>: add $0x5,%eax
0x00000000004003e9 <+9>: mov %eax,0x200c49(%rip) # 0x601038 <x>
7 }
We load c, add 5 and store to x.
So as you can see even with quite aggressive optimization (-O3) and the shortest program you can write, the effect of const is quite obvious.
g++ version 5.4.1

C and C++: Array element access pointer vs int

Is there a performance difference if you either do myarray[ i ] or store the adress of myarray[ i ] in a pointer?
Edit: The pointers are all calculated during an unimportant step in my program where performance is no criteria. During the critical parts the pointers remain static and are not modified. Now the question is if these static pointers are faster than using myarray[ i ] all the time.
For this code:
int main() {
int a[100], b[100];
int * p = b;
for ( unsigned int i = 0; i < 100; i++ ) {
a[i] = i;
*p++ = i;
}
return a[1] + b[2];
}
when built with -O3 optimisation in g++, the statement:
a[i] = i;
produced the assembly output:
mov %eax,(%ecx,%eax,4)
and this statement:
*p++ = i;
produced:
mov %eax,(%edx,%eax,4)
So in this case there was no difference between the two. However, this is not and cannot be a general rule - the optimiser might well generate completely different code for even a slightly different input.
It will probably make no difference at all. The compiler will usually be smart enough to know when you are using an expression more than once and create a temporary itself, if appropriate.
Compilers can do surprising optimizations; the only way to know is to read the generated assembly code.
With GCC, use -S, with -masm=intel for Intel syntax.
With VC++, use /FA (IIRC).
You should also enable optimizations: -O2 or -O3 with GCC, and /O2 with VC++.
I prefer using myarray[ i ] since it is more clear and the compiler has easier time compiling this to optimized code.
When using pointers it is more complex for the compiler to optimize this code since it's harder to know exactly what you're doing with the pointer.
There should not be much different but by using indexing you avoid all types of different pitfalls that the compiler's optimizer is prone to (aliasing being the most important one) and thus I'd say the indexing case should be easier to handle for the compiler. This doesn't mean that you should take care of aforementioned things before the loop, but pointers in a loop generally just adds to the complexity.
Yes. Having a pointer the address won't be calculated by using the initial address of the array. It will accessed directly. So you have a little performance improve if you save the address in a pointer.
But the compiler will usually optimize the code and use the pointer in both cases (if you have statical arrays)
For dynamic arrays (created with new) the pointer will offer you more performance as the compiler cannot optimize array accesses at compile time.
There will be no substantial difference. Premature optimization is the root of all evil - get a profiler before checking micro-optimizations like this. Also, the myarray[i] is more portable to custom types, such as a std::vector.
Okay so your questions is, whats faster:
int main(int argc, char **argv)
{
int array[20];
array[0] = 0;
array[1] = 1;
int *value_1 = &array[1];
printf("%d", *value_1);
printf("%d", array[1]);
printf("%d", *(array + 1));
}
Like someone else already pointed out, compilers can do clever optimization. Of course this is depending on where an expression is used, but normally you shouldn't care about those subtle differences. All your assumption can be proven wrong by the compiler. Today you shouldn't need to care about such differences.
For example the above code produces the following (only snippet):
mov [ebp+var_54], 1 #store 1
lea eax, [ebp+var_58] # load the address of array[0]
add eax, 4 # add 4 (size of int)
mov [ebp+var_5C], eax
mov eax, [ebp+var_5C]
mov eax, [eax]
mov [esp+88h+var_84], eax
mov [esp+88h+var_88], offset unk_403000 # points to %d
call printf
mov eax, [ebp+var_54]
mov [esp+88h+var_84], eax
mov [esp+88h+var_88], offset unk_403000
call printf
mov eax, [ebp+var_54]
mov [esp+88h+var_84], eax
mov [esp+88h+var_88], offset unk_403000
call printf
Short answer: the only way to know for sure is to code up both versions and compare performance. I would personally be surprised if there was a measureable difference unless you were doing a lot of array accesses in a really tight loop. If this is something that happens once or twice over the lifetime of the program, or depends on user input, it's not worth worrying about.
Remember that the expression a[i] is evaluated as *(a+i), which is an addition plus a dereference, whereas *p is just a dereference. Depending on how the code is structured, though, it may not make a difference. Assume the following:
int a[N]; // for any arbitrary N > 1
int *p = a;
size_t i;
for (i = 0; i < N; i++)
printf("a[%d] = %d\n", i, a[i]);
for (i = 0; i < N; i++)
printf("*(%p) = %d\n", (void*) p, *p++);
Now we're comparing a[i] to *p++, which is a dereference plus a postincrement (in addition to the i++ in the loop control); that may turn out to be a more expensive operation than the array subscript. Not to mention we've introduced another variable that's not strictly necessary; we're trading a little space for what may or may not be an improvement in speed. It really depends on the compiler, the structure of the code, optimization settings, OS, and CPU.
Worry about correctness first, then worry about readability/maintainability, then worry about safety/reliability, then worry about performance. Unless you're failing to meet a hard performance requirement, focus on making your intent clear and easy to understand. It doesn't matter how fast your code is if it gives you the wrong answer or performs the wrong action, or if it crashes horribly at the first hint of bad input, or if you can't fix bugs or add new features without breaking something.
Yes.. when storing myarray[i] pointer it will perform better (if used on large scale...)
Why??
It will save you an addition and may be a multiplication (or a shift..)
Many compilers may optimize that for you in case of static memory allocation.
If you are using dynamic memory allocation, the compiler will not optimize it, because it is in runtime!

changing the value of const variable in C++ [duplicate]

This question already has answers here:
Weird Behaviour with const_cast [duplicate]
(2 answers)
Closed 6 years ago.
I am trying to change the value of a variable which is defined as int const as below.
const int w = 10;
int* wp = const_cast <int*> (&w);
*wp = 20;
The value of w didn't change and was 10 even after the assignment, though it shows as if both w and wp are pointing to the same memory location. But I am able to the change the value of w, if defined as below while declaring
int i = 10;
const int w = i;
If I change the declaration of i to make it const like in
const int i = 10;
The value of w doesn't change.
In the first case, how come the value of w didn't change, even though w and wp point to the same memory location [ that was my impression I get when I print their addresses ]
What difference it's to the compiler that it treats both the cases differently?
Is there a way to make sure that w doesn't lose constness, irrespective of the way it is defined?
This is one of the cases where a const cast is undefined, since the code was probably optimized such that w isn't really a variable and does not really exist in the compiled code.
Try the following:
const volatile int w = 10;
int &wr = const_cast <int &> (w);
wr = 20;
std::cout << w << std::endl;
Anyhow, I would not advise abusing const_cast like that.
The code in the above example translates into the following assembler:
movl $10, 28(%esp) //const int i = 10;
leal 28(%esp), %eax //int* wp = const_cast <int*>(&i);
movl %eax, 24(%esp) //store the pointer on the stack
movl 24(%esp), %eax //place the value of wp in eax
movl $20, (%eax) //*wp = 20; - so all good until here
movl $10, 4(%esp) //place constant value 10 onto the the stack for use in printf
movl $.LC0, (%esp) // load string
call printf //call printf
Because the original int i was declared constant, the compiler reserves the right to use the literal value instead of the value stored on the stack. This means that the value does not get changed and you are stuck with the original 10.
The moral of the story is compile time constants should remain constant because that is what you are telling the compiler. The moral of the story is that casting away constness in order to change a constant can lead to bad things.
const_cast doesn't take away the const-ness of a variable as defined. If you were to pass a non-const variable by reference in to a method taking a const reference like void foo(const int& x) then you could use const_cast to modify the value of x within foo, but only if the variable you actually passed in was not const in the first place.
Why can't you just re-bind the constant? So instead of
const int w = 10;
int* wp = const_cast <int*> (&w);
*wp = 20;
// some code
just introduce the different constant with the same name
const int w = 10;
{
const int w = 20;
// the same code
}
If the "new" constant should depend on its own value, you should introduce another constant (const int _w = w; const int w = _w * 2;). The unnecessary assignments will be optimized out by compiler--because we've seen it has done such optimisation, as it's the reason why you asked your question.
You should not being changing the const value. There is a reason it is const and trying to change it will most likely just result in errors. If the const is stored in a read only memory section then you will get access violations.
Good question. I think the confusion comes from the fact that C++ uses the keyword ‘const’ for two different concepts depending on the context. These concepts are constant and read-only variables.
When a value of a ‘const’ variable can be calculated during the compilation, it creates a true constant. References to such constant are replaced with its value whenever it is used. That’s why there is no location in the memory that can be changed to affect all places where it is used. It is like using #define.
When value of a ‘const’ variable cannot be calculated during the compilation, it creates a read-only variable. It has a location in the memory that contains a value but compiler enforces a read-only behavior.
Here's a refresher, it should be noted that this is in C. This is a deceptively tricky underpinnings of the usage of a variable or pointer using the const keyword. This highlights the difference between the pointer variable foo and how the meaning of it can change by using the said keyword.
char const *foo;
char * const foo;
const char *foo;
The first and last declarations, makes the data pointed to by ‘foo’ read-only, but, you can change the address pointed to by ‘foo’ e.g.
const *char foo; /* OR char const *foo */
char str[] = "Hello";
foo = &str[0]; /* OK! */
foo[1] = 'h'; /* BZZZZTTT! Compile Fails! */
The middle declaration in the above, makes the pointer read-only, i.e. you cannot change the address of the data pointed to by ‘foo’
char * const foo;
char str[] = "Hello";
foo = &str[0]; /* BZZZZTTT! Compile Fails! */
My guess would be that declaring w const allows the compiler to perform more aggressive optimizations such as inlining w's value and reordering instructions. Wether w appears to change or not depends on which optimizations were applied in the precise case and is not under your control.
You can't force w to be totally const. The cons_cast should be a hint to the programmer that they might be doing something fishy.