After encountering some cast and const issues, I have simplified my problem in a very small code snippet:
#include <iostream>
using namespace std;
int main()
{
const int a = 2;
const int* p = &a;
int* p_bis = (int*)p;
*p_bis = 42;
printf("\na = %d", a);
printf("\n&a = %p\n", &a);
printf("\np = %p", p);
printf("\n*p = %d\n", *p);
printf("\np_bis = %p", p_bis);
printf("\n*p_bis= %d", *p_bis);
}
After compiling this in C++17, it gives me the following output:
a = 2
&a = 0x7ffe9924d19c
p = 0x7ffe9924d19c
*p = 42
p_bis = 0x7ffe9924d19c
*p_bis= 42
I know that the line int* p_bis = (int*)p; is very dirty, because I do a C cast instead of a clean C++ cast, and furthermore I remove the constness with my cast. But What I don't understand however is how is it possible to have 2 values at the same address 0x7ffe9924d19c. Is it just some undefined behavior, and there is nothing else to understand?
While it is perfectly valid to cast a const pointer to a non-const one, and it also is valid to modify data through that pointer if the data was not originally defined as const, it is invalid to do so if the data was originally defined as const (which is your case). Changing the value of a variable that was defined as const (even through indirection) is undefined behavior.
The above applies to any version of both C and C++.
Related
const int* additional(int* s, int* f){
const int* ts = reinterpret_cast<const int*>(*s + *f);
return ts;
}
int main() {
int a = 10, b = 20;
const int* oc = additional(&a, &b);
std::cout << *oc;
return 0;
}
I've tried using static, although it produces the same error
There are many things wrong with your code.
*s + *f is an int, not a pointer (you add the dereferenced values).
you are doing a reinterpret cast which isn't needed at all. Just pass the int's directly without pointers and you are good to go.
const int additional(int s, int f){
return s + f;
}
int main() {
int a = 10, b = 20;
const int oc = additional(a, b);
std::cout << oc;
return 0;
}
You reinterpret the number 30 as a pointer to const int and attempt to read through the reinterpreted pointer. The operating system noticed that the process was attempting to access an address wasn't mapped for the process and sent the segfault signal to terminate the process in order to protect the badly behaving process from itself.
Reinterpret casting is unsafe. Don't use it unless you know what you're doing. And when you know what you're doing, you'll know that it's quite rare to need to use it.
I was aiming to shorten the int t = *f + *s;
That is already extremely short. The function that you defined is much longer and so is even a call to the function. Note that the initialiser expression that you quote has type int while your function returns const int*. That, along with the broken reinterpret cast are the problem.
If you wanted to make the indirection shorter, then how about using references instead of pointers:
const int& f = a;
const int& s = b;
int t = a + b; // shorter
I ran into this example online and I can't figure out how it works for the life of me.
#include <iostream>
int main()
{
int const a = 1;
int* pa = (int*) &a;
*pa = 2;
printf("%p %d %p %d", (void*) &a, a, (void*) pa, *pa);
return 0;
}
When I compile it on my machine, I get:
0xffffcc04 1 0xffffcc04 2
Which means that the memory location 0xffffcc04 has value 1 and 2 simultaneously??? Is the compiler optimizing away a, or am I missing something?
P.S. when I run this in debug, a and *pa are 2...
Changing a const-value yields undefined behaviour, and the "mysterious" output is just such undefined behaviour.
It is actually needless to investigate on why a behaviour in the world of undefined behaviour is as it is then. But in your case it is probably not using a as you declare it as const, so the compiler "knows" the value and may decide not to access the variable.
Just for showing something curious, try:
int main()
{
volatile int const a = 1;
int* pa = (int*) &a;
*pa = 2;
printf("%p %d %p %d", (void*) &a, a, (void*) pa, *pa);
return 0;
}
I was surprised that c++ allows incrementing dereferenced pointer to a constant data, which it should not allow through a pointer to a const data. Consider the code:
#include<iostream>
#include<climits>
using namespace std;
int main(){
int x = 2;
const int *xPtr2 = &x;
*xPtr2++;
cout << x << endl;
}
But still the value of x is 2. That means *xPtr2 was not actually incremented. I also tried *xPtr2 = 3, but this time it shows compilation error. Why is it so?
Here the precedence of ++ is more than that of *. Hence
*xPtr2++
is equivalent to
*(xPtr2++)
Since xPtr2 is not a constant pointer but a pointer to constant data, incrementing xPtr2 and dereferencing it is fine in this case (but not others) and hence no compilation error is caused.
The ++ operator has precedence over dereferencing. Basically you're dereferencing the pointer that has been incremented.
For the behavior you're trying to accomplish, you should wrap the pointer in parens.
(*xPtr2)++;
Same goes for assigning - you're trying to assign an int to a int *. It would work with parens.
(*xPtr2) = 3;
See your example in ideone.
You have mentioned
dereferencing pointer to constant data
So, lets consider the following code
#include <stdio.h>
int main() {
const int foo = 0xdead;
int* bar = (int*) &foo;
*bar = 0xcafe;
printf("const int foo = %#x", foo);
return 0;
}
Output : const int foo = 0xcafe
In C, C++ const is just a compile time modifier for variables. This means that the compiler wants no modification to a const at compile time. At runtime there is no concept of const => all local variables are stored in stack, all static and global variables are stored in .data section. Thus you can dereference a const and modify it only at runtime
Here is my test code:
#define print(A) cout << #A << " = " << A << endl;
int main()
{
const int e = 2;
int *p = (int *)&e;
*p = 4;
print(e);
print(*p);
print(&e);
print(p);
}
Result:
e = 2;
*p = 4;
&e = 0xbfc6b458;
p = 0xbfc6b458;
Since "p" points to "e" according to their identical address, how can *p and "e" be different??? This can be dangerous, right?
Casting away const is legal; using the pointer (or reference) thus acquired to (attempt to) modify a const object is illegal.
Your code results in undefined behaviour; it can do anything and it doesn't have to make any sense.
Modifying a constant variable in any way results in an Undefined Behavior.
So yes this is dangerous.
An Undefined Behavior means that any behavior is possible and you cannot expect any valid behavior. The compiler is free to give you any results and it is allowed by the Standard to do so. Once an UB is invoked the program is not a valid program anymore.So best is to avoid any code which causes an UB.
They can be different because "e" is a const, so any decent compiler will plug in the value at compile time instead of reading it from memory.
Since you take the address there's still a "real" variable for it, but it's not actually used in your case.
And you're "lucky" that you could modify the value at all; since it was declared "const", the compiler could have placed it into readonly memory.
Either way, modifying a const value yields "undefined behavior". Lucky for us, you didn't destroy the world with your foolish game.
You're attempting to write to a constant variable (yes, the name is pretty oxymoron but I digress) which is undefined behavior.
You are casting away const. which is giving you wrong value which is Undefined behaviour.
It should be either
int e = 2;
int* p = (int *)&e;
*p = 4;
or
const int e = 2;
const int* p = (const int *)&e;
*p = 4;
latter one will give you compilation error as you are writting to a const.
Define variable:
const int e = 2;
directive const tell c/c++ compiler check whether L-value of e variable, compiler will prevent your code assign new value for e.
int* p = (int *)&e;
p is a pointer (also int 4 bytes), can be assigned any value , p = (((int *) e ) -2)+2. The compiler no need to check *p whether *p is constant. I think that is a flexible of c/c++ languages, the better way is avoiding pointer.
Here is some code I wrote (using GCC's __restrict__ extension to C++):
#include <iostream>
using namespace std;
int main(void) {
int i = 7;
int *__restrict__ a = &i;
*a = 5;
int *b = &i, *c = &i;
*b = 8;
*c = 9;
cout << **&a << endl; // *a - which prints 9 in this case
return 0;
}
Or, the C version (in case the C++ version is not clear due to the use of an extension which every popular C++ compiler supports), using GCC:
#include <stdio.h>
int main(void) {
int i = 7;
int *restrict a = &i;
*a = 5;
int *b = &i, *c = &i;
*b = 8;
*c = 9;
printf("%d \n", **&a); // *a - which prints 9 in this case
return 0;
}
From what I've read, if I do *a = 5, it changes the value of the memory he, a, is pointing to; after that, the memory to which he is pointing to should not be modified by anyone else except a, which means that these programs are wrong because b and c modify it after that.
Or, even if b modifies i first, after that only a should have access to that memory (i).
Am I getting it correctly?
P.S: Restrict in this program doesn't change anything. With or without restrict, the compiler will produce the same assembly code. I wrote this program just to clarify things, it is not a good example of restrict usage. A good example of restrict usage you can see here: http://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restrict-keyword.html
No.
Statements
*b = 8;
*c = 9;
will cause undefined behavior.
From documentation:
A pointer is the address of a location in memory. More than one pointer can access the same chunk of memory and modify it during the course of a program. The restrict type qualifier is an indication to the compiler that, if the memory addressed by the restrict-qualified pointer is modified, no other pointer will access that same memory. The compiler may choose to optimize code involving restrict-qualified pointers in a way that might otherwise result in incorrect behavior. It is the responsibility of the programmer to ensure that restrict-qualified pointers are used as they were intended to be used. Otherwise, undefined behavior may result.