I was asked how can a value of a const variable can be changed.
My my obvious answer was "pointers!" but I tried the next piece of code and I'm puzzled...
int main()
{
const int x = 5;
int *ptr = (int *)(&x); // "Cast away" the const-ness..
cout << "Value at " << ptr << ":"<< (*ptr) <<endl;
*ptr = 6;
cout << "Now the value of "<< ptr << " is: " << (*ptr) <<endl;
cout << "But the value of x is still " << x <<endl;
return 0;
}
And the output was:
Value at <some address> :5
Now the value of <same address> is: 6
But the value of x is still 5
Now, I'm not sure exactly what is returned from '&x' but it's definitely not the actual address of x, since the value at x wasn't changed!
But on the over hand, ptr did contain the value of x at the beginning!
So, what is it exactly?
EDIT compiled with VS2010
Your program invokes undefined behavior (writing to a const variable through a pointer is undefined behavior), so anything might happen. That being said here's the most likely explanation why you get the behavior you see on your particular implementation:
When you do &x, you do get the address of x. When you do *ptr = 6, you do write 6 to x's memory location. However when you do cout << x, you don't actually read from x's memory location because your compiler optimized the code by replacing x with 5 here. Since x is const the compiler is allowed to do that since there is no legal C++ program in which doing so would change the program's behavior.
Compiler caches x in a register, so the value in memory changes, but the last print-out is still the same. Check out generated assembly (compile with -s).
First of all, this behavior is undefined. That said, here's what's probably going on:
When you do this:
int *ptr = (int *)(&x);
The 5 is stored at some address at somewhere. That's why the pointer seems to work properly. (although casting away the const is still undefined behavior)
However, due to compiler optimizations x = 5 is just inlined as a literal in the final print statement. The compiler thinks it's safe because x is declared const.
cout << "But the value of x is still " << x <<endl;
That's why you print out the original value 5.
Maybe you are experiencing a side effect of code optimization, try to run the same code by disabling all optimization, or check at the asm generated code. I guess the compiler is reusing the value it has in some registry along the function since he bet on the const, so even if you are actually changing the value, the changed value is not propagated properly. The reasons for that as Keith noticed in the comemnts, is that you are palying with an undefined behavior.
What is returned from &x is a pointer to const int (i.e. int const*). Now pointers are inded implemented as holding the address, but pointers are not addresses, and your example shows quite nicely why: The type of the pointer, even though not present at run time, still plays an important role.
In your case, you are casting away the const, and thus lying to the compiler "this pointer points to a non-const int". However the compiler knows from the declaration that the value of x cannot change (it was declared const), and makes freely use of that fact (and the standard allows it: Your attempt to change it through a pointer to non-const int is undefined behaviour and therefore the compiler is allowed to do anything).
Related
I'm trying to understand pointers and I encounter this example.
If I have int MAX_VALUE = 90; the program behaves like I expected. But with const int MAX_VALUE = 90; it doesn't.
What is the explication?
#include <iostream>
using namespace std;
int main()
{
const int MAX_VALUE = 90;
cout << "Create variable in the heap." << endl;
int* a = new int;
*a = 2;
cout << "Point a to MAX_VALUE" << endl;
a = (int*)&MAX_VALUE; // Now a points to MAX_VALUE
cout << "Change content of a" << endl;
*a = 6; // Shouldn't this change the value of MAX_VALUE ??
cout << "Content of a: "<< *a << endl;
cout << "MAX_VALUE: " << MAX_VALUE << endl;
return 0;
}
Result:
Content of a: 6
MAX_VALUE: 90
But shouldn't MAX_VALUE change when I did *a = 6;?
I know you can't change const, but how does C++ handle it?
I have a pointing to MAX_VALUE, how can I change a and not MAX_VALUE?
As others have said, you're exploiting undefined behavior. In your case, your program is able to execute without crashing because your compiler's linker allocated space for the "constant" MAX_VALUE in RAM, and it was allocated in a RAM region whose attributes are not set as "read-only". I.e. it's being placed in writable RAM, even though you've declared it as const.
On another system, MAX_VALUE might be allocated in ROM (e.g. in an embedded system where the entire program is stored in memory-mapped flash space, and never copied to RAM). On such a system, you could try to write to MAX_VALUE all you wanted and it would never change, unless you knew the magic incantation pattern to trigger the flash memory's erase/program operations, in which case, yes it would change, but not to the value you wanted to change it to. (And if you triggered an erase operation, a whole lot of bytes around it would quickly change to all 0xFF's!) But that's really only possible on primitive embedded systems where the ROM address space isn't write-protected by an MMU, MPU, or by its chip-select configuration.
On yet another system, MAX_VALUE might be allocated in RAM, but in a section that's marked as read-only in the MMU/MPU. So even though the hardware would be physically capable of allowing its value to change at runtime, it is configured to trap/catch any attempt to do so, and will crash your program for an illegal access attempt (or other similar wording).
But as I said, on your system, since you can change the value of MAX_VALUE at runtime (bypassing compiler safety by casting away its const attribute), we know that on your system MAX_VALUE is allocated in writable RAM.
But then you're of course asking, how could the line...
cout << "MAX_VALUE: " << MAX_VALUE << endl;
...print 90 when you had previously changed its value to 6? Well, the compiler is allowed to optimize that line by not even performing a read of MAX_VALUE, using instead the initialization value from its definition, since in this compilation unit its initialization value is known. The const qualifier is a promise to the compiler that you won't be changing it, and at the same time, a request to the compiler that it alert you if you ever mistakenly try to change it. But by casting away the const attribute, you're bypassing that safety and the result is undefined behavior according to the C++ standard. In your case, your system will execute the code without crashing for the reasons I mentioned above.
It is because of compiler optimization. Since you have declared it as 'const', the compiler has optimized the "cout" to the actual value 90. So, it will not really use the value stored as MAX_VALUE. But I don't know why it is done even if we switch off the optimization.
If you watch the disassembly, you can see that the real value pushed is '5A' which is hex of 90
The problem is not so much that you are not allowed to change the value of *a but that the assignment of a const int* to an int* is not allowed by the C++ standard. If you remove your c-style cast the compiler will tell you so:
error: invalid conversion from ‘const int*’ to ‘int
15 | a = &MAX_VALUE; // Now a points to MAX_VALUE
| ^~~~~~~~~~
| |
| const int*
The reason that the compiler accepts your original code but produces a result that differs from your expectation is that casting away constness can lead to undefined behaviour (as it does in this situation).
The standard states in [dcl.type.cv] 10.1.7.:
Except that any class member declared mutable (10.1.1) can be modified, any attempt to modify a const object during its lifetime (6.8) results in undefined behavior.
(emphasis added)
And in your code MAX_VALUE refers to a const object, regardless of how you access it (e.g. through a).
Undefined behaviour means that while the compiler accepts the program and turns it into something, it is not defined what the result of this conversion is. For any program that exhibits undefined behaviour, the compiler is allowed to do literally anything it sees fit with your code. See also nasal demons.
As,you make MAX_VALUE as constant integer.You cannot change its value if once its value is specified.
You can learn more about constants here:
http://www.cplusplus.com/doc/tutorial/constants
Remove const from your code and problem will be solved
Constants refer to as fixed values, unlike variables whose value can be altered, constants - as the name implies does not change, they remain constant. Constant must have to be initialized at the time of creating it, and new values cannot be assigned later to it.
You can use the Variables if you want to alter the Value in it.
A variable provides us with named storage that our programs can manipulate and the set of operations that can be applied to the variable.
After reading about possible ways of rebinding a reference in C++, which should be illegal, I found a particularly ugly way of doing it. The reason I think the reference really gets rebound is because it does not modify the original referenced value, but the memory of the reference itself. After some more researching, I found a reference is not guaranteed to have memory, but when it does have, we can try to use the code:
#include <iostream>
using namespace std;
template<class T>
class Reference
{
public:
T &r;
Reference(T &r) : r(r) {}
};
int main(void)
{
int five = 5, six = 6;
Reference<int> reference(five);
cout << "reference value is " << reference.r << " at memory " << &reference.r << endl;
// Used offsetof macro for simplicity, even though its support is conditional in C++ as warned by GCC. Anyway, the macro can be hard-coded
*(reinterpret_cast<int**>(reinterpret_cast<char*>(&reference) + offsetof(Reference<int>, r))) = &six;
cout << "reference value changed to " << reference.r << " at memory " << &reference.r << endl;
// The value of five still exists in memory and remains untouched
cout << "five value is still " << five << " at memory " << &five << endl;
}
A sample output using GCC 8.1, but also tested in MSVC, is:
reference value is 5 at memory 0x7ffd1b4eb6b8
reference value changed to 6 at memory 0x7ffd1b4eb6bc
five value is still 5 at memory 0x7ffd1b4eb6b8
The questions are:
Is the method above considered undefined behavior? Why?
Can we technically say the reference gets rebound, even though it should be illegal?
In a practical situation, when the code has already worked using a specific compiler in a specific machine, is the code above portable (guaranteed to work in every operational system and every processor), assuming we use the same compiler version?
Above code has undefined behavior. The result of your reinterpret_cast<int**>(…) does not actually point to an object of type int*, yet you dereference and overwrite the stored value of the hypothetical int* object at that location, violating at least the strict aliasing rule in the process [basic.lval]/11. In reality, there is not even an object of any type at that location (references are not objects)…
Exactly one reference is being bound in your code and that happens when the constructor of Reference initializes the member r. At no point is a reference being rebound to another object. This simply appears to work due to the fact that the compiler happens to implement your reference member via a field that stores the address of the object the reference is refering to, which happens to be located at the location your invalid pointer happens to point to…
Apart from that, I would have my doubts whether it's even legal to use offsetof on a reference member to begin with. Even if it is, that part of your code would at best be conditionally-supported with effectively implementation-defined behavior [support.types.layout]/1, since your class Reference is not a standard-layout class [class.prop]/3.1 (it has a member of reference type).
Since your code has undefined behavior, it cannot possibly be portable…
As shown in the other answer, your code has UB. A reference cannot be re-boud - this is by language design and no matter what kind of casting trickery you try you cannot get around that, you will still end up with UB.
But you can have re-binding reference semantics with std::reference_wrapper:
int a = 24;
int b = 11;
auto r = std::ref(a); // bind r to a
r.get() = 5; // a is changed to 5
r = b; // re-bind r to b
r.get() = 13; // b is changed to 13
References can be rebound legally, if you jump through the right hoops:
#include <new>
#include <cassert>
struct ref {
int& value;
};
void test() {
int x = 1, y = 2;
ref r{x};
assert(&r.value == &x);
// overwrite the memory of r with a new ref referring to y.
ref* rebound_r_ptr = std::launder(new (&r) ref{y});
// rebound_r_ptr points to r, but you really have to use it.
// using r directly could give old value.
assert(&rebound_r_ptr->value == &y);
}
Edit: godbolt link. You can tell that it works because the function always returns 1.
This question already has an answer here:
Change "const int" via an "int *" pointer. Surprising and interesting [duplicate]
(1 answer)
Closed 6 years ago.
In c it's possible to change const using pointers like so:
//mainc.c
#include <stdio.h>
int main(int argc, char** argv) {
const int i = 5;
const int *cpi = &i;
printf(" 5:\n");
printf("%d\n", &i);
printf("%d\n", i);
printf("%d\n", cpi);
printf("%d\n", *cpi);
*((int*)cpi) = 8;
printf(" 8?:\n");
printf("%d\n", &i);
printf("%d\n", i);
printf("%d\n", cpi);
printf("%d\n", *cpi);
}
The constant is changed as can be seen in the output:
If we try the same in c++:
//main.cpp
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char** argv) {
const int i = 5;
const int *cpi = &i;
cout << " 5:" << '\n';
cout << &i << '\n';
cout << i << '\n';
cout << cpi << '\n';
cout << *cpi << '\n';
*((int*)cpi) = 8;
cout << " 8?:" << '\n';
cout << &i << '\n';
cout << i << '\n';
cout << cpi << '\n';
cout << *cpi << '\n';
int* addr = (int*)0x28ff24;
cout << *addr << '\n';
}
The result is not so clear:
From the output is looks like i is still 5 and is still located at 0x28ff24 so the const is unchanged. But in the same time cpi is also 0x28ff24 (the same as &i) but the value it points to is 8 (not 5).
Can someone please explain what kind of magic is happening here?
Explained here: https://stackoverflow.com/a/41098196/2277240
The behaviour on casting away const from a variable (even via a pointer or a reference in C++) that was originally declared as const, and then subsequently attempting to change the variable through that pointer or reference, is undefined.
So changing i if it's declared as const int i = 5; is undefined behaviour: the output you are observing is a manifestation of that.
It is undefined behavior as per C11 6.7.3/6:
If an attempt is made to modify an object defined with a
const-qualified type through use of an lvalue with non-const-qualified
type, the behavior is undefined.
(C++ will have a similar normative text.)
And since it is undefined behavior, anything can happen. Including: weird output, program crashes, "seems to work fine" (this build).
The rule of const_cast<Type *>() or c-type conversion (Type *):
The conversion is to remove const declaration, NOT to remove the const of the value (object) itself.
const Type i = 1;
// p is a variable, i is an object
const Type * p = &i; // i is const --- const is the property of i, you can't remove it
(Type *)p; // remove the const of p, instead the const of i ---- Here p is non-const but i is ALWAYS const!
Now if you try to change the value of i through p, it's Undefined Behavior because i is ALWAYS const.
When to use this kind of conversion?
1) If you can make sure that the pointed value is NOT const.
e.g.
int j = 1;
const int *p = &j;
*(int *)p = 2; // You can change the value of j because j is NOT const
2) The pointed value is const but you ONLY read it and NEVER change it.
If you really need to change a const value, please redesign you code to avoid this kind of case.
So after some thinking I guess I know what happens here. Though it is architecture/implementation dependent since it is undefined behaviour as Marian pointed out. My setup is mingw 5.x 32bit on windows 7 64 bit in case someone is interested.
C++ consts act like #defines, g++ replaces all i references with its value in compiled code (since i is a const) but it also writes 5 (i value) to some address in memory to provide acceses to i via pointer (a dummy pointer). And replaces all the occurences of &i with that adress (not exactly the compiler does it but you know what I mean).
In C consts are treated mostly like usual variables. With the only difference being that the compiler doesn't allow to change them directly.
That's why Bjarne Stroustrup says in his book that you don't need #defines in c++.
Here comes the proof:
It's a violation of the strict aliasing rule (the compiler assumes that two pointers of different types never reference the same memory location) combined with compiler optimization (the compiler is not performing the second memory access to read i but uses the previous variable).
EDIT (as suggested inside the comments):
From the working draft of the ISO C++ standard (N3376):
"If a program attempts to access the stored value of an object through
a glvalue of other than one of the following types the behavior is
undefined [...]
— a cv-qualified version of the dynamic type of the
object, [...]
— a type that is the signed or unsigned type
corresponding to a cv-qualified version of the dynamic type of the
object, [...]
— a type that is a (possibly cv-qualified) base class
type of the dynamic type of the object,"
As far as i understand it specifies, that a possibly cv-qualified type can be used as an alias, but not that a non cv qualified type for a cv qualified type can be.
It would be more fruitful to ask what one specific compiler with certain flags set does with that code than what “C” or “C++” does, because neither C nor C++ will do anything consistently with code like that. It’s undefined behavior. Anything could happen.
It would, for example, be entirely legal to stick const variables in a read-only page of memory that will cause a hardware fault if the program attempts to write to it. Or to fail silently if you try writing to it. Or to turn a dereferenced int* cast from a const int* into a temporary copy that can be modified without affecting the original. Or to modify every reference to that variable after the reassignment. Or to refactor the code on the assumption that a const variable can’t change so that the operations happen in a different order, and you end up modifying the variable before you think you did or not modifying it after. Or to make i an alias for other references to the constant 1 and modify those, too, elsewhere in the program. Or to break a program invariant that makes the program bug out in totally unpredictable ways. Or to print an error message and stop compiling if it catches a bug like that. Or for the behavior to depend on the phase of the moon. Or anything else.
There are combinations of compilers and flags and targets that will do those things, with the possible exception of the phase-of-the-moon bug. The funniest variant I’ve heard of, though, is that in some versions of Fortran, you could set the constant 1 equal to -1, and all loops would run backwards.
Writing production code like this is a terrible idea, because your compiler almost certainly makes no guarantees what this code will do in your next build.
The short answer is that C++ 'const' declaration rules allow it to use the constant value directly in places where C would have to dereference the variable. I.e, C++ compiles the statement
cout << i << '\n';
as if it what was actually written was
cout << 5 << '\n';
All of the other non-pointer values are the results of dereferencing pointers.
The other day, a C++ trainer said to me that "const" does have meaning only in compile time (statically) and thus doesn't have an influence in runtime... but when I test this example :
const int x = 5;
int * px = const_cast<int*>(&x);
*px = 10;
std::cout << "x = " << x <<std::endl; // x = 5 ???
x is not modified with 10 ! whereas, this example works as expected if we use pointers:
const int * x = new int(5);
int * px = const_cast<int*>(x);
*px = 10;
std::cout << "x = " << *x <<std::endl; // x = 10
So, this C++ trainer is wrong ?
It's undefined behaviour to modify a const T via const_cast. This allows the compiler to optimise your code assuming it never happens. In your first code example, the compiler probably inserted a literal 5 in the code during the call to operator<<.
Your second example is completely well defined, because x is really pointing at an int, not a const int. In this case, casting away the constness is fine.
It is Undefined Behaviour to strip away constness of variable that was declared as const in the first place.
Stripping away const of a const pointer or reference to non const variable is fine, but is not recomended.
I can't think of any assembly directive that actually derived from the C++ const keyword, so I guess there is no "run-time" actions being done in this part, but , declaring a variable as const may signal the compiler to store the variable in the data segement, or hard-code the value inside the assembly code directly without allocating its neccesery space (on the stack etc.). so assembly code that derived from a const variable may be look completly different from assembly code that was derived from mutable variable.
As other commenters mentioned it, you invoked undefined behaviour from the compiler by modifying an object which was originally declared const. const_castr is designed to strip away aquired constness, as when the object was declared modifiable, but than passed somewhere as const reference.
Your code actually borders on something else as well, which is also very dangerous. Have you defined your variable like this:
static const int x = 5;
You would also have a likely crash of your application. The reason for this is that variables declared like that are likely to be placed in read-only segment of the executable file, and modification to such a segement would cause a hardware abort.
This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
int main()
{
const int ia = 10;
int *pia = const_cast<int*>(&ia);
*pia = 5;
std::cout << &ia << "\t" << pia <<endl;
std::cout << ia << "\t" << *pia <<endl;
return 0;
}
The output is:
0x28fef4 0x28fef4
10 5
*pia and ia have the same address, but they have different values. My purpose is to use const_cast to modify a constant value, but as the result shows that it does not work.
Does anyone know why?
The reason why you see 10 printed for ia is most likely the compiler optimization: it sees a const object, decides that it's not going to change, and replaces the last printout with this:
cout<< 10 <<" "<<*ppa<<endl;
In other words, the generated code has the value of the const "baked into" the binary.
Casting away the const-ness of an object that has originally been declared as const and writing to that object is undefined behavior:
$5.2.11/7 - Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier68) may produce undefined behavior (7.1.5.1).
Depending on the platform, const objects may be placed in a protected region of memory, to which you cannot write. Working around the const-ness in the type system may help your program compile, but you may see random results or even crashes.
It is undefined behaviour to modify a constant value. Don't do it. If you need to modify the value, don't declare it as const.