3

Different sources say different things for me - some StackOverflow answers say that it is allocated at compile time - others say it is "defined" at compile time, and allocated at the very beginning of runtime ("load time" is what some called it), while others say it is allocated at compile time. When is static memory exactly allocated in C/C++? (if it is to do with "defining" variables - can someone tell me what it means to "define" a variable on the memory level - that would be highly appreciated!)

Also, how would you during runtime set a pointer to the start of the allocated static memory?

catfood
  • 345
  • 3
  • 14
  • 1
    when the program executes – Harry Oct 30 '20 at 17:47
  • 4
    _"...static storage duration. The storage for the object is allocated when the program begins and deallocated when the program ends...."_ - https://en.cppreference.com/w/cpp/language/storage_duration – Richard Critten Oct 30 '20 at 17:49
  • 3
    There is no such thing as "C/C++". – n. m. could be an AI Oct 30 '20 at 17:50
  • isn't the static memory concept kind of the same in both languages though? – catfood Oct 30 '20 at 17:53
  • 1
    From C perspective, the program starts *after* the runtime startup code is finished. – Eugene Sh. Oct 30 '20 at 17:53
  • 1
    It depends on actual code on C++ version. Note that `static` keyword has multiple meanings. So focus your question. – Marek R Oct 30 '20 at 17:55
  • 3
    The allocation of static memory is not an observable side effect, so the standard doesn't provide any guarantees on when it happens. From the standard itself, all we know is that the memory allocated at some point before the object is initialized. To know any more than that, you need to look at the particular implementation. – Brian Bi Oct 30 '20 at 17:56
  • 3
    @catfood even the static memory concept is kind of not the same in both languages... – Antti Haapala -- Слава Україні Oct 30 '20 at 17:56
  • @EugeneSh. could you clarify what you mean by this? – catfood Oct 30 '20 at 18:40
  • 1
    @catfood C program starts in `main`. Anything that is happening before that is mostly out of the C standard concern. – Eugene Sh. Oct 30 '20 at 18:43
  • ah I see - so things like function declarations before main are considered "runtime startup code" right? @EugeneSh. – catfood Oct 30 '20 at 18:44
  • 1
    No, no. It is not related to the functions you write in your C code, it is related to the functionality that happens behind the scenes, like initializing the stack, zeroing-out the .bss section and other platform specific stuff. In the end this code is calling your `main` and the execution starts. For hosted `gcc` programs it is usually in the `crt0.o` file which is linked automatically to your program. You can read about it – Eugene Sh. Oct 30 '20 at 18:47
  • Ah I see. I understand now. Thanks! – catfood Oct 30 '20 at 18:49
  • 1
    If I ever make my own programming language, I'm going to name it **C/C++**. – Eljay Oct 30 '20 at 19:07

3 Answers3

9

In typical tools, memory with static storage duration is arranged in multiple steps:

  • The compiler generates data in object modules (likely passing through some form of assembly code) that describes needs for various kinds of memory: memory initialized to zero, memory initialized to particular values and is read-only thereafter, memory initialized to particular values and may be modified, memory that does not need to be initialized, and possibly others. The compiler also includes initial data as necessary, information about symbols that refer to various places in the required memory, and other information. At this point, the allocation of memory is in forms roughly like “8 bytes are needed in the constant data section, and a symbol called foo should be set to their address.”
  • The linker combines this information into similar information in an executable file. It also resolves some or all information about symbols. At this point, the allocation of memory is in forms like “The initialized non-constant data section requires 3048 bytes, and here is the initial data for it. When it is assigned a virtual address, the following symbols should be adjusted: bar is at offset 124 from the start of the section, baz is at offset 900…”
  • The program loader reads this information, allocates locations in the virtual address space for it, and may read some of the data from the executable file into memory or inform the operating system where the data is to be found when it is needed. At this point, the places in the code that refer to various symbols have been modified according to the final values of those symbols.
  • The operating system allocates physical memory for the virtual addresses. Often, this is done “on demand” in pieces (memory pages) when a process attempts to access the memory in a specific page, rather than being done at the time the program is initially loaded.

All-in-all, static memory is not allocated at any particular time. It is a combination of many activities. The effect on the program is largely that it occurs the same as if it were all allocated when the program started, but the physical memory might only be allocated just before an instruction actually executes. (The physical memory can even be taken away from the process and restored to it later.)

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
8

The C standard says only this:

C11 5.1.2p1

[...]All objects with static storage duration shall be initialized (set to their initial values) before program startup. The manner and timing of such initialization are otherwise unspecified.

and

C11 6.2.4p2-3

2 The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address,33) and retains its last-stored value throughout its lifetime.34) If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

3 An object whose identifier is declared without the storage-class specifier _Thread_local, and either with external or internal linkage or with the storage-class specifier static, has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.

But... this is further made complicated by the as-if rule, the actual implementation need to do this only as far as observable side effects go.

In fact in Linux for example, one could argue that the variables with static storage duration are initialized and allocated by the compiler and the linker when producing executable file. When the program is run, the dynamic linker (ld.so) then prepares the program segments so that the initialized data is memory-mapped (mmap) from the executable image to RAM, default (zero-initialized) data is mapped from zeroed pages.

While the virtual memory is allocated by the compiler, linker and dynamic linker, the actual writable RAM page frames are allocated only when you write to a variable on a page for the first time...

but you do not need to know about this in basic cases. It is as if the memory for variables with static storage duration were allocated and initialized just before main was entered, even though this is not actually the case.

  • Why am I about to become only the second upvoter of this excellent answer? How times have changed! Look at the voting on this nonsense: https://stackoverflow.com/questions/3838242/minimum-date-in-java – Bathsheba Oct 30 '20 at 18:07
  • @Bathsheba: Because it's a a question of a kind that doesn't attract too many views because people don't usually think beyond "static is the allocation". – Joshua Oct 30 '20 at 18:08
  • Agree with Joshua. [Bike-shedding.](https://en.wikipedia.org/wiki/Law_of_triviality) – user4581301 Oct 30 '20 at 18:17
6

Static memory is allocated in two steps.

Step 1 is carried out by the linker as it lays out the executable image and says where the static variables live in relative address space.

Step 2 is carried out by the loader when the process memory is actually allocated.

In C++, static objects are initialized before entering main. If you're not careful with your code you can see objects that are still zeros even though they have constructors that would always change that. (The compiler does as much constant evaluation as it can, so toy examples won't show it.)

Joshua
  • 40,822
  • 8
  • 72
  • 132