Unexpected behavior 3!

In the following code it is clear that ptr holds an address
1
2
3
4
5
int nbr = 3;
int *ptr = &nbr;

std::cout << &nbr << std::endl;
std::cout << ptr << std::endl;


In the following code it is clear that ptr can be assigned another address
1
2
3
4
int *ptr2 = ptr;

std::cout << ptr << std::endl;
std::cout << ptr2 << std::endl;


But in the following code I cannot seem to assign an address directly
1
2
int *ptr2 = ptr;
ptr2 = 0x333333;


Why this not working?
Is there a way for that to work
> Why this not working?
Because you can't just invent addresses and go looking, at least not on machines running protected operating systems like Windows, Linux, Unix and Unix clones.

The OS doesn't instantly give you the entire 4GB address space (32-bit OS) to do with what you want.

The OS only maps enough virtual memory to store your program code stack and data.
https://www.geeksforgeeks.org/memory-layout-of-c-program/

Nor is your program loaded into the same place each time.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

int main () {
    int var;
    std::cout << "Main is at  "
              << reinterpret_cast<void*>(main)
              << std::endl;
    std::cout << "Stack is at "
              << reinterpret_cast<void*>(&var)
              << std::endl;
}

$ g++ foo.cpp
$ ./a.out 
Main is at  0x5609383b41e9
Stack is at 0x7fffadda9d14
$ ./a.out 
Main is at  0x55e0c91391e9
Stack is at 0x7ffc5d8fa1c4

See https://en.wikipedia.org/wiki/Address_space_layout_randomization
Is there a way for that to work

there are systems that not only allow this (which is a huge problem for security and stability both) like old DOS, but some embedded systems expect you do to this (but their libraries hide the addresses with names, etc). I had a programmable multi-switch where you set the voltage on the pins via an address this way, a long time ago, but it wasn't even a computer, it was just a device, and a very minimal device at that. It was basically setting memory locations in EEPROM type memory to tell it what to do when it was plugged in.

SO you may have to do it some day, but its not 'normal' coding and highly specific to the task at hand.

You can also look at memory this way, if you can get the OS to grant permission to you; virus scanners and system tools can read memory anywhere looking for problems. I am not sure how you do that in modern windows, but there is a way. You can force it, and assign a pointer a value, but it will likely crash your program even if you just try to read (ever see "access violation at address 0xblahblah" messages?)
Last edited on
I had a programmable multi-switch where you set the voltage on the pins via an address this way, a long time ago, but it wasn't even a computer, it was just a device, and a very minimal device at that. It was basically setting memory locations in EEPROM type memory to tell it what to do when it was plugged in.

This is common still
https://en.wikipedia.org/wiki/Memory-mapped_I/O
Last edited on
Why this not working?


because in L2 you have a type mismatch - you're trying to assign an int to a type pointer to int! If you want to commit kamikaze then:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

int main() {
	int nbr = 3;
	int* ptr = &nbr;

	std::cout << &nbr << std::endl;
	std::cout << ptr << std::endl;

	int* ptr2 = ptr;

	std::cout << ptr << std::endl;
	std::cout << ptr2 << std::endl;

	//ptr2 = 0x333333;	//NO 0x333333 is of type int and not int* !!
	ptr2 = (int*)0x333333;

	std::cout << ptr2 << std::endl;
}



00000000001FF9B0
00000000001FF9B0
00000000001FF9B0
00000000001FF9B0
0000000000333333


...just don't try to de-reference ptr2!
If this code compiled it would be very error-prone.
1
2
int *ptr2 = ptr;
ptr2 = 0x333333;

Because in most cases when you try to assign an integer to a pointer it's probably because you forgot to dereference the pointer.
 
*ptr2 = 0x333333;

If you really want to convert an integer to a pointer then you need to use a cast.
Last edited on
jonnin wrote:
some embedded systems expect you do to this (but their libraries hide the addresses with names, etc). I had a programmable multi-switch where you set the voltage on the pins via an address this way, a long time ago, but it wasn't even a computer, it was just a device, and a very minimal device at that. It was basically setting memory locations in EEPROM type memory to tell it what to do when it was plugged in.

I belive this is the sort of situation where you might want to use volatile, otherwise the compiler can optimize away reads and writes with the assumption that they don't have any side-effects.

For example, if the compiler sees something like this:
1
2
3
4
5
6
7
8
9
10
int* ptr = reinterpret_cast<int*>(0x333333);
*ptr = 1;
if (*ptr == 0)
{
	*ptr = 5;
}
else
{
	std::cout << *ptr << "\n";
}
it could optimize it to something like this:
1
2
3
int* ptr = reinterpret_cast<int*>(0x333333);
*ptr = 1;
std::cout << 1 << "\n";
but if the address is mapped to some memory-mapped hardware device this might not be at all what you want. Each write might be important and the value that you read might not be the same as you wrote earlier so to prevent the compiler from making these assumptions you can mark ptr as volatile.
1
2
volatile int* ptr = reinterpret_cast<int*>(0x333333);
...
Topic archived. No new replies allowed.