So, as of now, it seems to be impossible to actually modify a "const" value in C++ (tested in VS 2017).
const int a = 5;
int* ptr = (int*)&a; // Method 1
*((int*)(&a)) = 6; // Method 2
int* ptr = const_cast<int*>(&a); // Method 3
*ptr = 55;
cout << a << "\t" << &a << endl;
cout << *ptr << "\t" << ptr << endl;
Result:
5 SOMEMEMORYADDRESS
55 SOMEMEMORYADDRESS
Anyone got any idea what else can be tried to achieve the effect? Really curious how it is possible to have 1 memory address (at least according to the console) with 2 values.
Please note: there are topics like this for older C++ versions (and they used to work in the past - but they don't, anymore).
Really curious how it is possible to have 1 memory address (at least according to the console) with 2 values.
It's because you invoked undefined behavior. The C++ standard, from C++98, has expressly forbidden you from modifying an object that is declared const. And the standard has a catch-all statement such that if you do anything which causes modification of a const object, you get undefined behavior.
Because modifying an object declared const is UB, the compiler is free to assume that this object will never be modified. So, since the compiler can see that a is const and it is initialed to 5, it is 100% valid for the compiler to at compile time replace everything which revers to this object with 5. So when you do cout << a, the compiler is free to not bother to access memory; it can just do cout << 5.
If you did something to modify the memory behind a, that's UB, so the compiler doesn't have to care about what happens in that case.
they used to work in the past - but they don't, anymore
No, they never "worked". They merely just so happened to do what you thought they should. But C++ never guaranteed that compilers would behave in this way, so you have no right to complain about compilers changing that behavior now.
Related
#include<iostream>
using namespace std;
int main( )
{
int *p;
double *q;
cout << p << " " << q << endl;
p++;
q++;
cout << p << " " << q << endl;
//*p = 5; // should be wrong!
}
This function prints
0x7ffe6c0591a0 0
0x7ffe6c0591a4 0x8
Why does p point to some randm address and q to zero? Also, when I uncomment the line *p=5, shouln't it throw an error? It still works fine:
code with line uncommented output
0x7ffc909a2f70 0
0x7ffc909a2f74 0x8
What can explain this weird behaviour?
When local (auto) variables of basic type (int, double, pointers to them, etc) are uninitialised, any operation that accesses their value yields undefined behaviour.
Printing a variable accesses its value, so both the statements with cout << ... give undefined behaviour. Incrementing a variable also accesses its value (it is not possible to give the result of incrementing without accessing the previous value) so both the increment operators present undefined behaviour. Derefererencing an unitialised pointer (as in *p) gives undefined behaviour, as does assigning a value to the result *p = 5.
So every statement you have shown after the definitions of p and q gives undefined behaviour.
Undefined behaviour means there are no constraints on what is permitted to happen - or, more simply, that anything can happen. That allows any result from "appear to do nothing" to "crash" to "reformat your hard drive".
The particular output your are getting therefore doesn't really matter. You may get completely different behavior when the code is built with a different compiler, or even during a different phase of the moon.
In terms of a partial explanation of what you are seeing .... The variables p and q will probably receive values corresponding to whatever happens to be in memory at the location where they are created - and therefore to whatever some code (within an operating system driver, within your program, even within some other program) happened to write at that location previously. But that is only one of many possible explanations.
As you have not initialised the variables - the code resorts to undefined behaviour. So anything can happen including what you have experienced.
C++ gives you more than enough rope to hang yourself. Compile with all the warnings switched on to avoid some of the perils.
When you do not initiate a variable, it set to a random or specific value based on the compiler policy.
About ++ if you create a pointer to class A, and use ++ the pointer will be incremented by sizeof(A).
And about your last question, *p=5 is a good instance of undefined behavior when you did not allocate a memory for p;
This question already has answers here:
Two different values at the same memory address
(7 answers)
Closed 5 years ago.
I know that using const_cast is generally bad idea, but I was playing around with it and I came across a weird behaviour, where:
Two pointers have the same address value, yet when de-referenced, give different data values.
Does anyone have an explanation for this?
Code
#include <iostream>
int main()
{
const int M = 10;
int* MPtr = const_cast<int*>(&M);
(*MPtr)++;
std::cout << "MPtr = " << MPtr << " (*MPtr) = " << (*MPtr) << std::endl;
std::cout << " &M = " << &M << " M = " << M << std::endl;
}
Output
MPtr = 0x7fff9b4b6ce0 (*MPtr) = 11
&M = 0x7fff9b4b6ce0 M = 10
The program has undefined bahaviour because you may not change a const object.
From the C++ Standard
4 Certain other operations are described in this International
Standard as undefined (for example, the effect of attempting to modify
a const object). [ Note: This International Standard imposes no
requirements on the behavior of programs that contain undefined
behavior. —end note ]
So, aside from the "it's undefined behaviour" (which it is), the compiler is perfectly fine to use the fact that M is a constant, thus won't change, in the evaluation of cout ... << M << ..., so can use an instruction that has the immediate value 10, instead of the actual value stored in the memory of M. (Of course, the standard will not say how this works, more than "it's undefined", and compilers are able to choose different solutions in different circumstances, etc, etc, so it's entirely possible that you'll get different results if you modify the code, use a different compiler, different version of compiler or the wind is blowing in a different direction).
Part of the tricky bit with "undefined behaviour" is that it includes things that are "perfectly what you may expect" as well as "nearly what you'd expect". The compiler could also decide to start tetris if it discovers this is what you are doing.
And yes, this is very much one of the reasons why you SHOULD NOT use const_cast. At the very least NOT on things that were originally const - it's OK if you have something along these lines:
int x;
void func(const int* p)
{
...
int *q = const_cast<int *>(p);
*q = 7;
}
...
func(&x);
In this case, x is not actually const, it just becomes const when we pass it to func. Of course, the compiler may still assume that x is not changed in func, and thus you could have problems....
I'm trying to write a simple program to show how variables can be manipulated indirectly on the stack. In the code below everything works as planned: even though the address for a is passed in, I can indirectly change the value of c. However, if I delete the last line of code (or any of the last three), then this no longer applies. Do those lines somehow force the compiler to put my 3 in variables sequentially onto the stack? My expectation was that that would always be the case.
#include <iostream>
using namespace std;
void someFunction(int* intPtr)
{
// write some code to break main's critical output
int* cptr = intPtr - 2;
*cptr = 0;
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
someFunction(&a);
cout << a << endl;
cout << b << endl;
cout << "Critical value is (must be 3): " << c << endl;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl; //when commented out, critical value is 3
}
Your code causes undefined behaviour. You can't pass a pointer to an int and then just subtract an arbitrary amount from it and expect it to point to something meaningful. The compiler can put a, b, and c wherever it likes in whatever order it likes. There is no guaranteed relationship of any kind between them, so you you can't assume someFunction will do anything meaningful.
The compiler can place those wherever and in whatever order it likes in the current stack frame, it may even optimize them out if not used. Just make the compiler do what you want, by using arrays, where pointer arithmetic is safe:
int main()
{
int myVars[3] = {1,2,3};
//In C++, one could use immutable (const) references for convenience,
//which should be optimized/eliminated pretty well.
//But I would never ever use them for pointer arithmetic.
int& const a = myVars[0];
int& const b = myVars[1];
int& const c = myVars[2];
}
What you do is undefined behaviour, so anything may happen. But what is probably going on, is that when you don't take the adress of c by commenting out cout << &c << endl;, the compiler may optimize avay the variable c. It then substitutes cout << c with cout << 3.
As many have answered, your code is wrong since triggering undefined behavior, see also this answer to a similar question.
In your original code the optimizing compiler could place a, b and c in registers, overlap their stack location, etc....
There are however legitimate reasons for wanting to know what are the location of local variables on the stack (precise garbage collection, introspection and reflection, ...).
The correct way would then to pack these variables in a struct (or a class) and to have some way to access that structure (for example, linking them in a list, etc.)
So your code might start with
void fun (void)
{
struct {
int a;
int b;
int c;
} _frame;
#define a _frame.a
#define b _frame.b
#define c _frame.c
do_something_with(&_frame); // e.g. link it
You could also use array members (perhaps even flexible or zero-length arrays for housekeeping routines), and #define a _frame.v[0] etc...
Actually, a good optimizing compiler could optimize that nearly as well as your original code.
Probably, the type of the _frame might be outside of the fun function, and you'll generate housekeeping functions for inspecting, or garbage collecting, that _frame.
Don't forget to unlink the frame at end of the routine. Making the frame an object with a proper constructor and destructor definitely helps. The constructor would link the frame and the destructor would unlink it.
For two examples where such techniques are used (both because a precise garbage collector is needed), see my qish garbage collector and the (generated C++) code of MELT (a domain specific language to extend GCC). See also the (generated) C code of Chicken Scheme or Ocaml runtime conventions (and its <caml/memory.h> header).
In practice, such an approach is much more welcome for generated C or C++ code (precisely because you will also generate the housekeeping code). If writing them manually, consider at least fancy macros (and templates) to help you. See e.g. gcc/melt-runtime.h
I actually believe that this is a deficiency in C. There should be some language features (and compiler implementations) to introspect the stack and to (portably) backtrace on it.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Modifying a const through a non-const pointer
I'm studying C++, and very interesting about pointers. And I tried to change value of a constant value (my teacher called it backdoor, please clarify if I'm wrong) like this:
const int i = 0;
const int* pi = &i;
int hackingAddress = (int)pi;
int *hackingPointer = (int*)pi;
*hackingPointer = 1;
cout << "Address:\t" << &i << "\t" << hackingPointer << endl;
cout << "Value: \t" << i << "\t\t" << *hackingPointer << endl;
system("PAUSE");
return 0;
However, the result is very strange. Although the two addresses are the same, the values are different.
How is my code executed? And where is 0 and 1 value is stored exactly?
You've discovered a little thing that C++ developers call undefined behavior. You told the compiler that "i is a constant with the value 0". So when you ask the compiler for the value of i, it tells you that it is 0.
Mucking around with trying to change the value of a constant violates the assumptions made by the compiler (that constants are going to be, well, constant), and so, the compiler is going to generate invalid or inconsistent code.
There are a lot of situations in C++ where it is possible to do something without the compiler catching it as an error, but the result is undefined. And if you do that, then you get results like what you're seeing. The compiler does something weird and unexpected.
Oh, and if your teacher is trying to teach you anything from an example such as this, he's wrong, and you should be very scared.
The only guarantee you get from code like this is this:
the compiler can do literally anything it likes
When you write code, you have an implicit contract with the compiler:
"If I write well-defined C++ code, then you convert it into an executable with the same effects as described by the C++ standard".
When you do something like this, you violate the contract. And then the compiler isn't obliged to follow it either. If you give the compiler code that is not well-defined according to the C++ standard, then it can't, and isn't going to, create an executable which does as the C++ standard specifies.
It seems, that compiler has optimized (inlined int const value)
cout << "Value: \t" << i << "\t\t" << *hackingPointer << endl;
to
cout << "Value: \t" << 0 << "\t\t" << *(0x0044ff28) << endl;
Anyway, you have still succeeded to change value of memory where i is stored. But do not try this at home :-)
It is not permitted to change the values of a constant, in fact it's undefined behaviour so your program could do anything as a result.
In this instance it looks like your compiler optimised the read away at compile time because it knew the value is fixed. Lots of implementations might just crash when you try and change it, but you cannot and should not bet or rely upon the result of any undefined behaviour ever.
Check this example for const_cast of int.
I am using VC++ 2008 to compile this.
#include <iostream>
using namespace std;
void main() {
const int x=0;
int y=90;
int *p = const_cast<int *> (&x);
*p=y;
cout<<" value of x: "<<x<<" addr of x "<<&x<<endl
<<" and *p : "<<*p<<" and addr p "<<p<<endl;
}
================
The output is
value of x: 0 addr of x 0012FF60
and *p : 90 and addr p 0012FF60
You should not const_cast a variable defined as const. I don't have the standard at hand but I'm fairly certain it defines such an operation as resulting in undefined behaviour.
For an example of why this results in undefined behaviour consider an MCU where things defined as const are stored in non-volatile memory (flash, EEPROM or something even less volatile).
There's more to read in the C++ FAQ Lite.
For the following program
#include <iostream>
int main() {
const int x=0;
int y=90;
int *p = const_cast<int *> (&x);
*p=y;
std::cout << " value of x: " << x << " addr of x " << &x << '\n'
<< " and *p : " << *p << " and addr p " << p << '\n';
return 0;
}
VC9 prints the same address for me. However:
You are invoking undefined behavior, because you are not allowed to cast away const from an object if that object was a real const value. (OTOH, you are, for example, allowed to cast away const from a const reference if that reference refers to a non-const value.)
In theory, when you invoke undefined behavior, according to the C++ standard your program might work as you expect, or it might not, or it might do so only on Sundays, or unless it's a holiday and full moon. But it might just as well format your HD, blow up your monitor, and make your girlfriend pregnant. According to the C++ standard, all this (and an infinite amount of other possibilities), are Ok.
In practice, such a program might print out funny addresses.
The compiler might completely optimize away all your code and just put in dummy values for printing. It shouldn't, however, do so for Debug builds. (Although that's a QoI issue, not a requirement.)
The compiler is optimizing away the aliasing. Try it in debug mode, with optimizations disabled.
edit
The compiler is optimizing away the aliasing, yes, but it's not an error in the optimization. Rather, the code is doing something undefined, which is leading to an unwanted but legal behavior. Staffan's answer clarifies this.
As the FAQ said, in almost all cases where you're tempted to use const_cast, you should be using mutable instead. If, as in the sample code here, you can't use mutable, this is an indication that something might be wrong.
maybe it was optimized by the compiler. he have all rights to do this.
it is drawback of misusing const_cast.
never use const_cast in such way.