const char * foo()
{
return "abcdef";
}
int main()
{
printf("%s", foo());
}
Can a conforming compiler decide to allocate "abcdef"
on the stack? I.e. what in the standard forces the compiler to allocate it in the .data
section?
const char * foo()
{
return "abcdef";
}
int main()
{
printf("%s", foo());
}
Can a conforming compiler decide to allocate "abcdef"
on the stack? I.e. what in the standard forces the compiler to allocate it in the .data
section?
From the C++ specification § 2.14.5/8 for string literals;
Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n
const char
”, where n is the size of the string as defined below, and has static storage duration (3.7).
It is also worthwhile mentioning this, static storage duration, applies to all the string literals; hence L""
, u""
, U""
etc; § 2.14.5/10-12.
In turn, for the static storage duration § 3.7.1/1;
All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program (3.6.2, 3.6.3).
Hence, your string "abcdef"
shall exist for the duration of the program. The compiler can choose where to store it (and this may be a system constraint), but it must remain valid.
For the C language specification (C11 draft n1570), string literals § 6.4.5/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. For character string literals, the array elements have type
char
, and are initialized with the individual bytes of the multibyte character sequence.
And the static storage duration § 6.2.4/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.
The same rationale for the location applies (it will most likely be a system constraint), but must remain valid for the duration of the program.
what in the standard forces the compiler to allocate it on the .data section?
Nothing. But it can certainly not be on the stack, since pointers to a string literal must never be invalidated (as the literal has static storage duration1), and values on the stack get overwritten by other frames at some point. And objects with static storage duration usually lie on a section dedicated to that - the .data
section.
Under the as-if rule, he could put it on the stack if the observable behavior of the program doesn't change; That is very unlikely to happen though, since that wouldn't benefit the performance of the program in any way (and nonsensical relevant compilers are yet to be written).
1) [lex.string]/8:
Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n
const char
”, where n is the size of the string as defined below, and has static storage duration (3.7).
Referring to N1570 (C11 draft) 6.4.5/6
String literals (emphasis mine going forward):
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.78) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type
char
, and are initialized with the individual bytes of the multibyte character sequence.
This means that string literals have lifetime of whole execution of program, as mentioned in 6.2.4/3
Storage durations of objects:
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 specifierstatic
, 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.
It's unlikely that compiler places them on stack, due to its nature (hint: preservation between functions' calls).
Note that C Standard does not explicitely forbid to place string literals on the stack. In fact it does not even define such term as stack nor .data
section. It's up to compiler, to choose whatever data placement, that is conformant with the Standard.
Previous answers have already quoted from the standard, so I'll go with the logical approach instead.
You can copy this literal string from the RO-data section into the stack every time the function is called:
const char* foo()
{
const char str[] = "abcdef";
return str;
}
But this function returns a pointer.
And you most certainly do not want this pointer to contain an address in the stack.
So it makes no sense to have that literal string allocated on the stack to begin with.
Everything of static duration must remain allocated until the program exits; it would be possible for such things to be located on the stack, but only if they are allocated before any user code is executed. Such a design would be unusual, but might be advantageous in e.g. a plug-in architecture where it was desired to have several threads run a plug-in simultaneously and have every thread's instance behave completely independently. If the architecture would have all instances of a plug-in share the same static data, then at least from the standpoint of the plug-in architecture, data which shouldn't be shared shouldn't be static. While it might arguably be better to have each instance store its static data in a block of space requested from the heap, that would necessitate having each instance free up that block of space when it was done. Having each plug-in instance allocate all its data on its stack (including a suitable-sized char[]
that which would be subdivided to satisfy malloc()
or new
requests) prior to running user code would ensure that killing the thread associated with an instance would free up the storage associated with it.