After compilation, what does the reference become, an address, or a constant pointer?
I know the difference between pointers and references, but I want to know the difference between the underlying implementations.
int main()
{
int a = 1;
int &b = a;
int *ptr = &a;
cout << b << " " << *ptr << endl; // 1 1
cout << "&b: " << &b << endl; // 0x61fe0c
cout << "ptr: " << ptr << endl; // 0x61fe0c
return 0;
}
The pedantic answer is: Whatever the compiler feels like, all that matters is that it works as specified by the language's semantics.
To get the actual answer, you have to look at resulting assembly, or make heavy usage of Undefined Behavior. At that point, it becomes a compiler-specific question, not a "C++ in general" question
In practice, references that need to be stored essentially become pointers, while local references tend to get compiled out of existence. The later is generally the case because the guarantee that references never get reassigned means that if you can see it getting assigned, then you know full well what it refers to. However, you should not be relying on this for correctness purposes.
For the sake of completeness
It is possible to get some insight into what the compiler is doing from within valid code by memcpying the contents of a struct containing a reference into a char buffer:
#include <iostream>
#include <array>
#include <cstring>
struct X {
int& ref;
};
int main() {
constexpr std::size_t x_size = sizeof(X);
int val = 12;
X val_ref = {val};
std::array<unsigned char, x_size> raw ;
std::memcpy(&raw, &val_ref, x_size);
std::cout << &val << std::endl;
std::cout << "0x";
for(const unsigned char c : raw) {
std::cout << std::hex << (int)c;
}
std::cout << std::endl ;
}
When I ran this on my compiler, I got the (endian flipped) address of val stored within the struct.
it heavily depend on compiler maybe compiler decide to optimize the code therefore it will make it value or ..., but as far i know references will compiler like pointer i mean if you see their result assembly they are compiled like pointer.
int main()
{
int a = 2; // address is 0x7ffeefbff58c
int *b = &a;
std::cout << "address of a: " << b << std::endl;
return 0;
}
I have my int variable a at address 0x7ffeefbff58c, but can I directly assign int* b with 0x7ffeefbff58c?
I tried int * b = 0x7ffeefbff58c;
But there is an error says "cannot initialize a variable of type 'int *' with an rvalue of type 'long'", so do I have to use the address of a (&a) to initialize the pointer? or there is other way to do it?
can I directly assign int* b with 0x7ffeefbff58c?
Technically, yes.
If so, how to do that?
With reinterpret cast.
But do realise that there is absolutely no guarantee in general that a would be in the address 0x7ffeefbff58c. As such, there isn't much that you can do with such integer reinterpreted as a pointer. Doing this with a local variable would be pointless.
A case where interpreting integer as a pointer is useful is some embedded systems that reserve some constant memory addresses for special purposes.
Heere is an example:
#include <iostream>
int main()
{
int *b = (int*) 0x7ffeefbff58c;
std::cout << "b: " << b << std::endl;
return 0;
}
after compilation and execution you will see output:
b: 0x7ffeefbff58c
This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 6 years ago.
I have these two almost identical bits of c++
#include <iostream>
using namespace std;
int main(){
int a = 0;
int b = 1;
int c = 2;
int d = 3;
int *p = &a;
cout << &c << endl;
cout << *(p+1);
}
with the output:
0x7ffd7b16998c
2
and
#include <iostream>
using namespace std;
int main(){
int a = 0;
int b = 1;
int c = 2;
int d = 3;
int *p = &a;
cout << &d << endl;
cout << *(p+1);
}
which produces the output:
0x7ffdb7ea105c
3
Why does the value of *(p+1) depend on what I output beforehand?
If I delete the line
cout << &c << endl;
completely i get the expected 1 as an output.
What on earth is happening?
What's happening is undefined behavior.
When you obtain a pointer to an int, you are allowed to use the value of that pointer alone; pointer arithmetic is meaningless.
In order for p+1 to produce an address that you can dereference, p must point to an array element other than its last element. In all other situations, reading *(p+1) is undefined.
Standards aside, the CPU must be taking that value from some place. You assume that the place must be the address of b, which is declared immediately after a. However, C++ makes no guarantees about location of local variables in memory relative to each other. It appears that the compiler reorders your variables, producing an output that you did not expect (and it's undefined anyway).
*(p+1) accesses memory after a so it's Undefined Behaviour.
Propably you intended (*p)+1 to increase a by 1?
This question already has answers here:
Why does std::cout output disappear completely after NULL is sent to it
(3 answers)
Closed 8 years ago.
I'm learning about pointers in C++. I wrote this simple program to show what I had a problem with:
#include <iostream>
using namespace std;
int main() {
cout << "test1";
char *ptr = 0;
cout << ptr;
cout << "test2";
}
When I run the program, it doesn't output "test2" at the end, instead only "test1". This should mean that it crashed when I tried to print out the value of ptr? I tried stepping through it in Eclipse debugger and it looks like every line gets executed but doesn't it throw an error or something?
char *ptr = 0;
cout << ptr;
There's an overload of the << operator that takes a char* operand, which it assumes is a pointer to a C-style string.
For pointer types other than char*, the << operator would print the value of the pointer (which is an address), but treating a null char* pointer as if it pointed to a C-style string causes undefined behavior. In any case, it's not going to print the pointer value.
To print the pointer value, you can convert it to void*:
cout << "test1\n";
char *ptr = 0;
cout << static_cast<void*>(ptr) << "\n";
cout << "test2" << "\n";;
Normally you can output a pointer to cout and it will print the address contained. However, when you output a char * it is interpreted as a C-style null-terminated string. In this case, it's a null pointer and does not point to a string.
Try casting it to a void * before outputting it.
I realized, what if i define const int into the body of c++ function and then use the address arithmetic to change the value of the constant( its on the stack, isn't it? ). i got this code:
const int a = 10;
int b = 100;
int * c = &b;
c++;
cout << "&a: " << &a << endl;
cout << " c: " << c << endl;
*c = 100500;
cout << " a: " << a << endl;
cout << "*c: " << *c << endl;
and i got this output
&a: 0x7ffff63866a8
c: 0x7ffff63866a8
a: 10
*c: 100500
So, addresses are the same, but values are different. Can someone explain me this result? Thanks!
p.s. i tried on GCC, Clang and VS
Can someone explain me this result?
As with any attempt to access objects in invalid ways via invalid pointer arithmetic or other shenanigans: undefined behaviour.
What is happening here is that the compiler is assuming that the value of a won't change, and optimising it to be a compile-time constant. It's allowed to do that, since you've declared it const and thereby stated that it won't change.
its on the stack, isn't it?
Since you also take the address of it (when you print &a), it does get allocated an address on the stack; but there's no need for the program to read from that address to get the value, since it's already known to be 10.
Of course, this is all undefined, so the program would be just as valid if it ordered you a pizza instead.
Your program has undefined behavior written all over it...
The assumption that incrementing the address of b will get you to a is bogus, it could or it could not. You are then using what is called in the standard unsafely derived pointer to modify a const object (a) which is also undefined behavior. Anything can happen.
What really happens (in your implementation, explanation of your results but you cannot depend on this as this is undefined behavior) is that you forced the allocation of a in the stack by means of taking its address, and you got a pointer into it. You modified that value, and the address in memory is updated. But, in the expression: cout << " a: " << a << endl; the compiler knows that a is a constant, and thus its value can only be 10, so it transformed the code into cout << " a: " << 10 << endl; to avoid having to go to memory to obtain the value.
const int a = 10;
int b = 100;
OK.
int * c = &b;
OK, but silly and my bug-o-meter is starting to twiddle.
c++;
Bug-o-meter now in the yellow zone.
cout << "&a: " << &a << endl;
OK
*c = 100500;
Bug-o-meter pegged. Undefined Behavior invoked. World explodes, you get fired.
c++ moves the pointer to the next int in memory. The pointer math is OK, but all you can use c for at this point is to compare the pointer to another pointer. You can't dereference the pointer in any way. But that's what you do when you try to assign through it.
What happens next is irrelevant and, honestly, misleading. You think that c now points to the same memory as b, and maybe it does. But it's only through Undefined Behavior that this happened. You might also think that the value of *c is what you expect it to be, but this result is false. Maybe it is, maybe it isn't. You shattered the vial when you opened the box -- the cat is dead. And so is your program.
And by the way, if what you're trying to do is find a way to cheat the compiler so that you can change a const, don't -- it is strictly forbidden to change a const by any means.
There is a const_cast in C++, but that is also not a mechanism that you can use to change a const.
its on the stack, isn't it?
No, your expectations are wrong. C++ has no notion of stack whatsoever, much less of how different automatic variables are stored in memory relative to each other. What you are trying to do is plain Undefined Behaviour.
In your very case, the compilers optimize a away, because they are allowed to by the standard, and the results you're getting don't have to make any sense since it's UB anyway.
The C++ compiler will simply assume that you will never try to change the value of a const variable.
This doesn't mean that if you do you will get an error... just that the compiler authors can ignore what is going to happen and anything that happens will be classified as "your fault".
SSCC:
#include <stdio.h>
int main ()
{
const int a = 10;
int b = 100;
int *c = &b;
printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
a, b, *c, (void *)&a, (void *)&b, (void *)c);
c++; // "c" now invalid
printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
a, b, *c, (void *)&a, (void *)&b, (void *)c);
*c = 100500; // Undefined behavior!
printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
a, b, *c, (void *)&a, (void *)&b, (void *)c);
return 0;
}
EXAMPLE OUTPUT:
a=10, b=100, *c=100; &a=0028FF18, &b=0028FF14, c=0028FF14
a=10, b=100, *c=10; &a=0028FF18, &b=0028FF14, c=0028FF18
a=10, b=100, *c=100500; &a=0028FF18, &b=0028FF14, c=0028FF18
CASE 2 - WE DON'T TRY TO TAKE ADDRESSOF CONST A:
#include <stdio.h>
int main ()
{
const int a = 10;
int b = 100;
int *c = &b;
printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
a, b, *c, (void *)&b, (void *)c);
c++; // "c" now invalid
printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
a, b, *c, (void *)&b, (void *)c);
*c = 100500; // Undefined behavior!
printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
a, b, *c, (void *)&b, (void *)c);
return 0;
}
SAMPLE OUTPUT
a=10, b=100, *c=100; &b=0028FF14, c=0028FF14
a=10, b=100, *c=2686744; &b=0028FF14, c=0028FF18
a=10, b=100, *c=0; &b=0028FF14, c=00018894