Why are strings statically allocated in C?

Viewed 131

In C (at least) local string variables are allocated in the .rodata section or .data segment generally.

int main(){
    char string[] = "hello world!"; //this is allocated statically in the .rodata section not in the stack.
}

Why not store them on the stack, since it is a local variable? Will the string data be in memory for the full execution time? Is that not a waste of memory?

3 Answers

The C Standard doesn't really define concepts such as "stack allocation" and program "data segments"; instead, it uses the general concept of an "abstract machine".

However, for string literals (an example of which is your "hello world!"), it does specify something about their storage. In the example you have given, you appear to have some confusion between the nature of – and storage for – the string[] array and the nature of the string literal that is used to initialize that array (see Clifford's answer for more on that difference).

From this C11 Draft Standard1 (bold emphasis mine):

6.4.5 String Literals

…
6      In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.

Thus, in order to conform to the Standard, a C compiler cannot place such a literal 'on the stack' and it must ensure that the created data remains 'alive' for the full duration of program execution.


1 The relevant section in this C17 Draft Standard has no significant change.

How have you drawn the conclusion that string is statically allocated? It is not. The literal string you are using as an initialiser is what is in .rodata.

It is possible that as an optimisation, if string is never modified that the compiler will translate all references to it to references to the literal string. In your example however it is also likely that the optimiser will eradicate it altogether since it is neither read, written or referenced.

Consider:

#include <stdio.h>
int main()
{
    volatile int stack_var = 0 ;
    volatile char string[] = "hello world!" ;
    printf( "&stack_var = %p\n", &stack_var ) ;
    printf( "&string = %p\n", string ) ;
    printf( "&\"literalstring\" = %p\n", "literal string" ) ;

}

Then consider the veracity of your assertion.

Example output from the above code at https://onlinegdb.com/BZ9yITMFY:

&stack_var = 0x7fff22144974
&string = 0x7fff2214497b
&"literalstring" = 0x55c3b4d86023

Clearly the string literal, is in an entirely different region than both stack_var and string and it is likely that what you are observing is the location of the literal initialiser string "hello world!" and not the location of the variable string. The initialiser data is copied to string on instantiation. Moreover if it were a local variable in a function, it will be reinstantiated and therefore re-initialised every time the function is called.

Further consider:

const char string2[] = "another" ;
const char* string3 = "one more" ;
&string2 = 0x7ffd029fa573
&string3 = 0x5590b3376058

string3 refers directly to the string literal and occupies no stack space in this case, so if you want a symbol that refers to a constant (read-only) string, that is the most memory efficient method.

That said it is common in C to use macros for string literal symbols:

#define STRING4 "A Literal String"

which then relies on the linker to amalgamate duplicate string literals (which any reasonable linker will do, but it is not a requirement). Unlike string3 however STRING4 can itself be used as an initialiser.

Why not store them on the stack, since it is a local variable?

"The stack" only exists at runtime - once the program terminates, any data that is stored there ceases to exist. The "hello world!" string literal that is used to initialize the string array has to somehow be persisted between runs of the program, so it's stored as part of the program image itself in segments like .rodata.

Of course, depending on how you use the string array and how aggressively the code is optimized, storage for it may not be allocated at all; if you never try to update its contents or take the address of it or any of its elements, the compiler may simply replace all references to it with references to the literal.

Related