13

I have an issue - with the following code I am trying to find out what is stored at a certain address and how long my static variable is stored at this specific position. (I read that static variables are stored infinitely and was quite surprised - wanted to test if this was true). The code defines a static variable (its address on my system is 0x1000020c0 - This is probably rather random but was continuously the case)

If I now want to find out what integer value is stored at this address I have to first print out the address with $number, which then gives 0x1000020c0. The recasting/reinterpreting of the address (0x1000020c0) gives 100 only! if the address was printed before or if I use &number in the reinterpreting/recasting.

Can someone explain why this is the case?

int static number = 100;  

//  std::cout << number << std::endl; <- prints 100

//  prints 100 and the address 0x1000020c0 in my case
//  std::cout << number << " " << &number << std::endl;

//  this does not work unless &number is printed previously
//  std::cout << "Value is :  " << *reinterpret_cast<int*>(0x1000020c0) << std::endl;

// this does work and show the correct value (100)
std::cout << "Value is :  " << *reinterpret_cast<int*>(&number) << std::endl;
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Maik Ro
  • 320
  • 1
  • 11
  • Because most likely the variable isn't in that memory address when the code is different. – Sami Kuhmonen Feb 20 '17 at 07:58
  • 5
    "stored infinitely" only means for the lifetime of the program, not literally until the end of time. – pjc50 Feb 20 '17 at 11:24
  • 2
    Read about [the as-if rule](http://stackoverflow.com/questions/15718262/what-exactly-is-the-as-if-rule). You have a naive unjustified mental model for c++ & unfounded beliefs about what c++ programs & particular operators do. A language/library manual/reference/specification tells you what you can expect when a program runs; you have no right to expect anything else. – philipxy Feb 20 '17 at 12:09
  • Define "it does not work". – Lightness Races in Orbit Feb 20 '17 at 13:38
  • If you're writing C++, and unless you're working in a niche, it would be better to forget about addresses and low-level details and just code to the abstraction that C++ provides. Your source code is not a list of instructions for your computer to execute; it is a description of a program semantics. What problem are you trying to solve, actually? – Lightness Races in Orbit Feb 20 '17 at 13:46

3 Answers3

19

In any given program, the object might, or might not be stored in the address 0x1000020c0. There are no guarantees either way. The address of the object is decided at compile (or possibly at link) time. A change to the program can change the address.

If you never take the address of the local static object, and never modify it, the compiler may optimize the variable away, so that no memory is used. If the object doesn't exist at all, then it definitely doesn't exist at the memory location 0x1000020c0.

If you use the object in a way that requires the object to exist, it will be in some memory location. Taking the address of the object usually triggers such requirement. This is strikingly similar to observer effect in physics.

If you dereference a pointer which does not point to an object (of appropriate type), the behaviour is undefined.


when I print recast/reinterpret the value that is at 0x1000020c0 it prints nothing

As I explained above, the object is not guaranteed to exist at the memory location 0x1000020c0.

even though the object was used since i printed its value via std::cout << number;

Accessing the value of an object doesn't necessarily require the object to exist. The compiler may be able to prove that the value of the object is 100, so it can store that value as a constant and not store static object at all.

Besides, even if the static object did exist, it wouldn't necessarily exist in the address 0x1000020c0, unless you take the address and observe it to be so.


As a consequence: Don't ever cast an arbitrary number to a pointer (unless you work on some embedded platform that has hardcoded memory mappings). Seeing that the address of an object in one program is 0x1000020c0, doesn't make 0x1000020c0 non-arbitrary in another program.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • So then please explain, why when I print only number it still does not work - the address which is found under &number is still empty... – Maik Ro Feb 20 '17 at 08:08
  • @MaikR what do you mean by "address is still empty"? – eerorika Feb 20 '17 at 08:09
  • when I print recast/reinterpret the value that is at 0x1000020c0 it prints nothing - even though the object was used since i printed its value via std::cout << number; – Maik Ro Feb 20 '17 at 08:12
  • ok I might be a little slow so please correct me if I'm wrong - 1. the static variable can be modified (for faster programs) by the compiler and does not necessarily have to exist at the given address. 2. the address that I receive after printing &number does not necessarily have to be the address that the object is stored in unless I ask for the address specifically with the &number command? – Maik Ro Feb 20 '17 at 08:34
  • 1
    @Maik - Sort of. If you print the address of a variable, the compiler will have to give that variable an address. If not, it might just use the value 100, and never store it anywhere. It's like the old philosophy question: *If a tree falls in the woods and nobody is there to listen, does it make a sound?* (the observer effect). – Bo Persson Feb 20 '17 at 09:13
  • 2
    This is why you should program within the abstraction provided by C++, instead of treating your source code as a list of instructions executed by your computer (it's not!) – Lightness Races in Orbit Feb 20 '17 at 13:40
2
  1. Assuming specific address of number is not the best idea.
  2. In C++, static inside a function body is created at first invocation or when first time C++ program flow encounters the variable. They are never created if never used.
  3. If possible, a compiler may choose to optimize the static and replace it with the value.
Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • So then please explain, why when I print only number it still does not work - the address which is found under &number is still empty... – Maik Ro Feb 20 '17 at 08:04
  • 1
    @MaikR Because compiler can optimize away the variable completely and use `100` to print the number. You can use `g++ -O2 -fdump-tree-optimized` to verify this. Output I got is `_4 = std::basic_ostream::operator<< (&cout, 100);[...] std::__ostream_insert > (&cout, "Value is : ", 12);` – Mohit Jain Feb 20 '17 at 08:13
  • The very last sentence is misleading, because `static` is an overloaded term. You describe function-scope `statics`, but statics at global scope exist outside program flow, and aren't created on first use. – MSalters Feb 20 '17 at 08:24
  • The state "life starts" is not correct enough. "A constructor called" is the more correct state. A memory for int is allocated in link-time if the variable "number" not eliminated by compiler optimization. – KonstantinL Feb 20 '17 at 08:24
0

You're missing one very major statement here - the platform you're running this code on.

A static variable isn't stored "infinitely"; it's stored in that location for the duration of the program execution. If you're running on an embedded platform where your code jumps to main() at power-up, then you don't have anything else which will get in the way. If you're running on any other platform (Windows, Linux or whatever), that location becomes free when the program completes, and is immediately available for anything else to use.

It's possible that if you run your program, it completes, and you run it again, then maybe you'll get the same chunk of memory for your program to run in. In that case you'll get the same addresses for static variables. If something else has asked for a chunk of memory between your first run finishing and the next run starting (e.g. Chrome needed a bit more space for the pictures you were browsing), then your program won't be given the same chunk of memory and the variable won't be in the same place.

It gets more fun for DLLs. The same kind of rules apply, except they apply for the duration of the DLL being loaded instead of for the duration of program execution. A DLL could be loaded on startup and stay loaded all the way through, or it could be loaded and unloaded by applications as needed.

All this means that you're making some very strange assumptions. If you get the address of a static variable in your program, and then your program checks the contents of that address, you'll always get whatever's in that static variable. That's how static variables work. If you run your code twice, you'll be getting the address of the location for that static variable at your next run, as set up by your program when you run it that second time. In between runs of your program, that address is 100% free for anything else to use.

As others have already pointed out, after this you may also be seeing effects of compiler optimisation in the specific behaviour you're asking about. But the reason you're asking about this specific behaviour is that you seem to have misunderstood something fundamental to how static variables work.

Graham
  • 1,655
  • 9
  • 19
  • Memory allocations in another process should not effect the address received, as they are in a completely separate address space in most systems. – user1937198 Feb 20 '17 at 15:31
  • @user1937198 You've misunderstood what I wrote. Memory allocations in another process will not affect your program while it runs. But any memory allocations by other code between your program finishing and being run for the second time, or other programs stopping and starting, *will* affect where your program's code and data live in memory. If by "most systems" you mean Linux and PCs, actually they aren't really separate address spaces, because everything runs from RAM. – Graham Feb 20 '17 at 16:24
  • Hey Graham, thank you for the answer but I think you got me wrong. I understand that static variables only exist for the run-time of the program, however there was this book stating that the exist infinitely and I wanted to test if I was right and they were wrong. Therefore, I used the construct above to identify the address of the variable and when it was the same for 5 runs or so I assumed that for the time being this would be the address I could find my value at. However I was surprised and unaware of compiler optimization - so I learned something today -> it was a good day. – Maik Ro Feb 20 '17 at 21:03
  • @graham yes the physical location will change, but this is invisible to the program as it is handled by a combination of the kernel + MMU. Other processes should not effect the virtual address which is from the processes point of view the only address. Since we are talking about virtual addresses here the fact the physical address can change is irrelevant. – user1937198 Feb 20 '17 at 21:25
  • Also the physical address can change whilst the program is running. If the page is paged out, then paged back in it will page in at a different physical address. This is one of the many reasons programs do not get access to the physical addresses. – user1937198 Feb 20 '17 at 21:28
  • @user1937198 OK, I see what you mean, and you're right. But from the OP's perspective (within the application), he's not going to to see that from within his application either. – Graham Feb 21 '17 at 10:15