C++ class constant-value member -- style - c++

My question related to style and underlying efficiency, if there's a difference at all, for effectively static member variables.
Consider:
class C {
public:
static const int const_m = 13;
static const int const_n = 17;
};
class D {
public:
enum : int { const_m = 13 };
enum : int { const_n = 17 };
};
In both cases I can write (in a main() fcxn):
int main() {
int cm = C::const_m;
int cn = C::const_n;
int dm = D::const_m;
int dn = D::const_n;
}
so the result is the same, and the coding style looks the same. In class C, the value of const_m will be put in the static section of the compiled code, and const_m will refer to the address of this value. In class D, the enum is part of the memory footprint of the class.
I've called g++ -S on both these classes and looked the trivial main() function above. I've also done this with -O0 and -O3 and I can see no different in the asm code. The key ops that correspond to the c++ code above are:
movl $13, -4(%rbp)
movl $17, -8(%rbp)
movl $13, -12(%rbp)
movl $17, -16(%rbp)
Is there a consideration that I'm missing when electing to use one style or the other?
Thanks in advance, -Jay
Edit
class C {
public:
static constexpr int const_m = 13;
static constexpr int const_n = 17;
};
ensures that const_m is compile-time available.

I don't believe you can use the static const to size an array for example, because they aren't technically required to be compile time constants.

Efficiency should definitely be the same for the two choices here. They are "compile time constants", so the compiler will be able to use the value directly without complication.
As to which is "better" from a style perspective, I think it really depends on what you are trying to achieve and what the meaning of the constants are. Enum's are definitely my choice if you have a number of different constants that are closely related, where the static const int makes more sense if it's just a single, standalone constant (max_size or magic_file_marker_value).
As touched on in the other answer, it's possible to come up with a situation where a static const int something = ...; is not a compile time constant - e.g.
static const time_t seed = time(NULL);
This would not allow you to then use it where a compile-time constant is needed [such as array sizes], because although it's a CONSTANT from many perspectives, it is not a compile time known value.

Related

When is a constexpr evaluated at compile time?

What assurances do I have that a core constant expression (as in [expr.const].2) possibly containing constexpr function calls will actually be evaluated at compile time and on which conditions does this depend?
The introduction of constexpr implicitly promises runtime performance improvements by moving computations into the translation stage (compile time).
However, the standard does not (and presumably cannot) mandate what code a compiler produces. (See [expr.const] and [dcl.constexpr]).
These two points appear to be at odds with each other.
Under which circumstances can one rely on the compiler resolving a core constant expression (which might contain an arbitrarily complicated computation) at compile time rather than deferring it to runtime?
At least under -O0 gcc appears to actually emit code and call for a constexpr function. Under -O1 and up it doesn't.
Do we have to resort to trickery such as this, that forces the constexpr through the template system:
template <auto V>
struct compile_time_h { static constexpr auto value = V; };
template <auto V>
inline constexpr auto compile_time = compile_time_h<V>::value;
constexpr int f(int x) { return x; }
int main() {
for (int x = 0; x < compile_time<f(42)>; ++x) {}
}
When a constexpr function is called and the output is assigned to a constexpr variable, it will always be run at compiletime.
Here's a minimal example:
// Compile with -std=c++14 or later
constexpr int fib(int n) {
int f0 = 0;
int f1 = 1;
for(int i = 0; i < n; i++) {
int hold = f0 + f1;
f0 = f1;
f1 = hold;
}
return f0;
}
int main() {
constexpr int blarg = fib(10);
return blarg;
}
When compiled at -O0, gcc outputs the following assembly for main:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 55
mov eax, 55
pop rbp
ret
Despite all optimization being turned off, there's never any call to fib in the main function itself.
This applies going all the way back to C++11, however in C++11 the fib function would have to be re-written to use conversion to avoid the use of mutable variables.
Why does the compiler include the assembly for fib in the executable sometimes? A constexpr function can be used at runtime, and when invoked at runtime it will behave like a regular function.
Used properly, constexpr can provide some performance benefits in specific cases, but the push to make everything constexpr is more about writing code that the compiler can check for Undefined Behavior.
What's an example of constexpr providing performance benefits? When implementing a function like std::visit, you need to create a lookup table of function pointers. Creating the lookup table every time std::visit is called would be costly, and assigning the lookup table to a static local variable would still result in measurable overhead because the program has to check if that variable's been initialized every time the function is run.
Thankfully, you can make the lookup table constexpr, and the compiler will actually inline the lookup table into the assembly code for the function so that the contents of the lookup table is significantly more likely to be inside the instruction cache when std::visit is run.
Does C++20 provide any mechanisms for guaranteeing that something runs at compiletime?
If a function is consteval, then the standard specifies that every call to the function must produce a compile-time constant.
This can be trivially used to force the compile-time evaluation of any constexpr function:
template<class T>
consteval T run_at_compiletime(T value) {
return value;
}
Anything given as a parameter to run_at_compiletime must be evaluated at compile-time:
constexpr int fib(int n) {
int f0 = 0;
int f1 = 1;
for(int i = 0; i < n; i++) {
int hold = f0 + f1;
f0 = f1;
f1 = hold;
}
return f0;
}
int main() {
// fib(10) will definitely run at compile time
return run_at_compiletime(fib(10));
}
Never; the C++ standard permits almost the entire compilation to occur at "runtime". Some diagnostics have to be done at compile time, but nothing prevents insanity on the part of the compiler.
Your binary could be a copy of the compiler with your source code appended, and C++ wouldn't say the compiler did anything wrong.
What you are looking at is a QoI - Quality of Implrmentation - issue.
In practice, constexpr variables tend to be compile time computed, and template parameters are always compile time computed.
consteval can also be used to markup functions.

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

Does static constexpr variable inside a function make sense?

If I have a variable inside a function (say, a large array), does it make sense to declare it both static and constexpr? constexpr guarantees that the array is created at compile time, so would the static be useless?
void f() {
static constexpr int x [] = {
// a few thousand elements
};
// do something with the array
}
Is the static actually doing anything there in terms of generated code or semantics?
The short answer is that not only is static useful, it is pretty well always going to be desired.
First, note that static and constexpr are completely independent of each other. static defines the object's lifetime during execution; constexpr specifies that the object should be available during compilation. Compilation and execution are disjoint and discontiguous, both in time and space. So once the program is compiled, constexpr is no longer relevant.
Every variable declared constexpr is implicitly const but const and static are almost orthogonal (except for the interaction with static const integers.)
The C++ object model (§1.9) requires that all objects other than bit-fields occupy at least one byte of memory and have addresses; furthermore all such objects observable in a program at a given moment must have distinct addresses (paragraph 6). This does not quite require the compiler to create a new array on the stack for every invocation of a function with a local non-static const array, because the compiler could take refuge in the as-if principle provided it can prove that no other such object can be observed.
That's not going to be easy to prove, unfortunately, unless the function is trivial (for example, it does not call any other function whose body is not visible within the translation unit) because arrays, more or less by definition, are addresses. So in most cases, the non-static const(expr) array will have to be recreated on the stack at every invocation, which defeats the point of being able to compute it at compile time.
On the other hand, a local static const object is shared by all observers, and furthermore may be initialized even if the function it is defined in is never called. So none of the above applies, and a compiler is free not only to generate only a single instance of it; it is free to generate a single instance of it in read-only storage.
So you should definitely use static constexpr in your example.
However, there is one case where you wouldn't want to use static constexpr. Unless a constexpr declared object is either ODR-used or declared static, the compiler is free to not include it at all. That's pretty useful, because it allows the use of compile-time temporary constexpr arrays without polluting the compiled program with unnecessary bytes. In that case, you would clearly not want to use static, since static is likely to force the object to exist at runtime.
In addition to given answer, it's worth noting that compiler is not required to initialize constexpr variable at compile time, knowing that the difference between constexpr and static constexpr is that to use static constexpr you ensure the variable is initialized only once.
Following code demonstrates how constexpr variable is initialized multiple times (with same value though), while static constexpr is surely initialized only once.
In addition the code compares the advantage of constexpr against const in combination with static.
#include <iostream>
#include <string>
#include <cassert>
#include <sstream>
const short const_short = 0;
constexpr short constexpr_short = 0;
// print only last 3 address value numbers
const short addr_offset = 3;
// This function will print name, value and address for given parameter
void print_properties(std::string ref_name, const short* param, short offset)
{
// determine initial size of strings
std::string title = "value \\ address of ";
const size_t ref_size = ref_name.size();
const size_t title_size = title.size();
assert(title_size > ref_size);
// create title (resize)
title.append(ref_name);
title.append(" is ");
title.append(title_size - ref_size, ' ');
// extract last 'offset' values from address
std::stringstream addr;
addr << param;
const std::string addr_str = addr.str();
const size_t addr_size = addr_str.size();
assert(addr_size - offset > 0);
// print title / ref value / address at offset
std::cout << title << *param << " " << addr_str.substr(addr_size - offset) << std::endl;
}
// here we test initialization of const variable (runtime)
void const_value(const short counter)
{
static short temp = const_short;
const short const_var = ++temp;
print_properties("const", &const_var, addr_offset);
if (counter)
const_value(counter - 1);
}
// here we test initialization of static variable (runtime)
void static_value(const short counter)
{
static short temp = const_short;
static short static_var = ++temp;
print_properties("static", &static_var, addr_offset);
if (counter)
static_value(counter - 1);
}
// here we test initialization of static const variable (runtime)
void static_const_value(const short counter)
{
static short temp = const_short;
static const short static_var = ++temp;
print_properties("static const", &static_var, addr_offset);
if (counter)
static_const_value(counter - 1);
}
// here we test initialization of constexpr variable (compile time)
void constexpr_value(const short counter)
{
constexpr short constexpr_var = constexpr_short;
print_properties("constexpr", &constexpr_var, addr_offset);
if (counter)
constexpr_value(counter - 1);
}
// here we test initialization of static constexpr variable (compile time)
void static_constexpr_value(const short counter)
{
static constexpr short static_constexpr_var = constexpr_short;
print_properties("static constexpr", &static_constexpr_var, addr_offset);
if (counter)
static_constexpr_value(counter - 1);
}
// final test call this method from main()
void test_static_const()
{
constexpr short counter = 2;
const_value(counter);
std::cout << std::endl;
static_value(counter);
std::cout << std::endl;
static_const_value(counter);
std::cout << std::endl;
constexpr_value(counter);
std::cout << std::endl;
static_constexpr_value(counter);
std::cout << std::endl;
}
Possible program output:
value \ address of const is 1 564
value \ address of const is 2 3D4
value \ address of const is 3 244
value \ address of static is 1 C58
value \ address of static is 1 C58
value \ address of static is 1 C58
value \ address of static const is 1 C64
value \ address of static const is 1 C64
value \ address of static const is 1 C64
value \ address of constexpr is 0 564
value \ address of constexpr is 0 3D4
value \ address of constexpr is 0 244
value \ address of static constexpr is 0 EA0
value \ address of static constexpr is 0 EA0
value \ address of static constexpr is 0 EA0
As you can see yourself constexpr is initilized multiple times (address is not the same) while static keyword ensures that initialization is performed only once.
Not making large arrays static, even when they're constexpr can have dramatic performance impact and can lead to many missed optimizations. It may slow down your code by orders of magnitude. Your variables are still local and the compiler may decide to initialize them at runtime instead of storing them as data in the executable.
Consider the following example:
template <int N>
void foo();
void bar(int n)
{
// array of four function pointers to void(void)
constexpr void(*table[])(void) {
&foo<0>,
&foo<1>,
&foo<2>,
&foo<3>
};
// look up function pointer and call it
table[n]();
}
You probably expect gcc-10 -O3 to compile bar() to a jmp to an address which it fetches from a table, but that is not what happens:
bar(int):
mov eax, OFFSET FLAT:_Z3fooILi0EEvv
movsx rdi, edi
movq xmm0, rax
mov eax, OFFSET FLAT:_Z3fooILi2EEvv
movhps xmm0, QWORD PTR .LC0[rip]
movaps XMMWORD PTR [rsp-40], xmm0
movq xmm0, rax
movhps xmm0, QWORD PTR .LC1[rip]
movaps XMMWORD PTR [rsp-24], xmm0
jmp [QWORD PTR [rsp-40+rdi*8]]
.LC0:
.quad void foo<1>()
.LC1:
.quad void foo<3>()
This is because GCC decides not to store table in the executable's data section, but instead initializes a local variable with its contents every time the function runs. In fact, if we remove constexpr here, the compiled binary is 100% identical.
This can easily be 10x slower than the following code:
template <int N>
void foo();
void bar(int n)
{
static constexpr void(*table[])(void) {
&foo<0>,
&foo<1>,
&foo<2>,
&foo<3>
};
table[n]();
}
Our only change is that we have made table static, but the impact is enormous:
bar(int):
movsx rdi, edi
jmp [QWORD PTR bar(int)::table[0+rdi*8]]
bar(int)::table:
.quad void foo<0>()
.quad void foo<1>()
.quad void foo<2>()
.quad void foo<3>()
In conclusion, never make your lookup tables local variables, even if they're constexpr. Clang actually optimizes such lookup tables well, but other compilers don't. See Compiler Explorer for a live example.

how to assign multiple values into a struct at once?

I can do this on initialization for a struct Foo:
Foo foo = {bunch, of, things, initialized};
but, I can't do this:
Foo foo;
foo = {bunch, of, things, initialized};
So, two questions:
Why can't I do the latter, is the former a special constructor for initialization only?
How can I do something similar to the second example, i.e. declare a bunch of variables for a struct in a single line of code after it's already been initialized? I'm trying to avoid having to do this for large structs with many variables:
Foo foo;
foo.a = 1;
foo.b = 2;
foo.c = 3;
//... ad infinitum
Try this:
Foo foo;
foo = (Foo){bunch, of, things, initialized};
This will work if you have a good compiler (e.g. GCC).
Update: In modern versions of C (but not C++), you can also use a compound literal with designated initializers, which looks like this:
foo = (Foo){ .bunch = 4, .of = 2, .things = 77, .initialized = 8 };
The name right after the "." should be the name of the structure member you wish to initialize. These initializers can appear in any order, and any member that is not specified explicitly will get initialized to zero.
The first is an aggregate initializer - you can read up on those and tagged initializers at this solution:
What is tagged structure initialization syntax?
It is a special initialization syntax, and you can't do something similar after initialization of your struct. What you can do is provide a member (or non-member) function to take your series of values as parameters which you then assign within the member function - that would allow you to accomplish this after the structure is initialized in a way that is equally concise (after you've written the function the first time of course!)
In C++11 you can perform multiple assignment with "tie" (declared in the tuple header)
struct foo {
int a, b, c;
} f;
std::tie(f.a, f.b, f.c) = std::make_tuple(1, 2, 3);
If your right hand expression is of fixed size and you only need to get some of the elements, you can use the ignore placeholder with tie
std::tie(std::ignore, f.b, std::ignore) = some_tuple; // only f.b modified
If you find the syntax std::tie(f.a, f.b, f.c) too code cluttering you could have a member function returning that tuple of references
struct foo {
int a, b, c;
auto members() -> decltype(std::tie(a, b, c)) {
return std::tie(a, b, c);
}
} f;
f.members() = std::make_tuple(1, 2, 3);
All this ofcourse assuming that overloading the assignment operator is not an option because your struct is not constructible by such sequence of values, in which case you could say
f = foo(1, 2, 3);
Memory Footprint - Here is an interesting i386 addition.
After much hassle, using optimization and memcpy seems to generate the smallest footprint using i386 with GCC and C99. I am using -O3 here. stdlib seems to have all sorts of fun compiler optimizations at hand, and this example makes use of that (memcpy is actually compiled out here).
Do this by:
Foo foo; //some global variable
void setStructVal (void) {
const Foo FOO_ASSIGN_VAL = { //this goes into .rodata
.bunch = 1,
.of = 2,
.things = 3,
.initialized = 4
};
memcpy((void*) &FOO_ASSIGN_VAL, (void*) foo, sizeof(Foo));
return;
}
Result:
(.rodata) FOO_ASSIGN_VAL is stored in .rodata
(.text) a sequence of *movl FOO_ASSIGN_VAL, %registers* occur
(.text) a sequence of movl %registers, foo occur
Example:
Say Foo was a 48 field struct of uint8_t values. It is aligned in memory.
(IDEAL) On a 32-bit machine, this COULD be as quick as 12 MOVL instructions of immediates out to foo's address space. For me this is 12*10 == 120bytes of .text in size.
(ACTUAL) However, using the answer by AUTO will likely generate 48 MOVB instructions in .text. For me this is 48*7 == 336bytes of .text!!
(SMALLEST*) Use the memcpy version above. IF alignment is taken care of,
FOO_ASSIGN_VAL is placed in .rodata (48 bytes),
12 MOVL into %register
12 MOVL outof %registers are used in .text (24*10) == 240bytes.
For me then this is a total of 288 bytes.
So, for me at least with my i386 code,
- Ideal: 120 bytes
- Direct: 336 bytes
- Smallest: 288 bytes
*Smallest here means 'smallest footprint I know of'. It also executes faster than the above methods (24 instructions vs 48). Of course, the IDEAL version is fastest & smallest, but I still can't figure that out.
-Justin
*Does anyone know how to get implementation of 'IDEAL' above? It is annoying the hell out of me!!
If you don't care too much about efficiency, you could double assign: i.e. create a new instance of the structure using aggregate initialization, and then copy it over:
struct Foo foo;
{
struct Foo __tmp__ = {bunch, of, things, initialized};
foo = __tmp__;
}
Make sure you keep the portion wrapped in {}s so as to discard the unnecessary temporary variable as soon as it's no longer necessary.
Note this isn't as efficient as making, e.g., a 'set' function in the struct (if c++) or out of the struct, accepting a struct pointer (if C). But if you need a quick, preferably temporary, alternative to writing element-by-element assignment, this might do.
If you care about efficiency, you can define a union of the same length as your structure, with a type you can assign at once.
To assign values by elements use the struct of your union, to assign the whole data, use the other type of your union.
typedef union
{
struct
{
char a;
char b;
} Foo;
unsigned int whole;
} MyUnion;
MyUnion _Union;
_Union.Foo.a = 0x23; // assign by element
_Union.Foo.b = 0x45; // assign by element
_Union.whole = 0x6789; // assign at once
Be carefull about your memory organization (is "a" the MSB or the LSB of "whole"?).

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.