可以在堆栈上分配const静态字符串吗?

qdi*_*dii 21 c c++ memory

const char * foo()
{
    return "abcdef";
}

int main()
{
    printf("%s", foo());
}
Run Code Online (Sandbox Code Playgroud)

符合标准的编译器是否可以决定"abcdef"在堆栈上进行分配?即标准中的内容强制编译器在该.data部分中分配它?

Nia*_*all 25

来自C++规范§2.14.5/ 8的字符串文字;

普通字符串文字和UTF-8字符串文字也称为窄字符串文字.窄字符串文字的类型为" n的 数组const char",其中n是下面定义的字符串的大小,并且具有静态存储持续时间(3.7).

值得一提的是,静态存储持续时间适用于所有字符串文字 ; 因此L"",u"",U""等; §2.14.5/ 10-12.

反过来,对于静态存储持续时间§3.7.1/ 1;

所有没有动态存储持续时间,没有线程存储持续时间且不是本地的变量都具有静态存储持续时间.这些实体的存储应持续到程序的持续时间(3.6.2,3.6.3).

因此,您的字符串"abcdef"应在程序的持续时间内存在.编译器可以选择存储它的位置(这可能是系统约束),但它必须保持有效.

对于C语言规范(C11 draft n1570),字符串文字§6.4.5/ 6;

在转换阶段7中,将值为零的字节或代码附加到由字符串文字或文字产生的每个多字节字符序列.然后使用多字节字符序列初始化静态存储持续时间和长度的数组,数组足以包含序列.对于字符串文字,数组元素具有类型char,并使用多字节字符序列的各个字节进行初始化.

静态存储时间§6.2.4/ 3;

如果对象的标识符是在没有存储类说明符的情况下声明的_Thread_local,并且具有外部或内部链接或者存储类说明符为static,则具有静态存储持续时间.它的生命周期是程序的整个执行,它的存储值只在程序启动之前初始化一次.

该位置的相同原理适用(它很可能是系统约束),但必须在程序的持续时间内保持有效.


Col*_*mbo 6

标准中的内容强制编译器在.data部分分配它?

没有.但它肯定不会在堆栈上,因为指向字符串文字的指针永远不会失效(因为文字具有静态存储持续时间1),并且堆栈上的值在某些时候被其他帧覆盖.具有静态存储持续时间的对象通常位于专用于该.data部分的部分上.

在as-if规则下,如果程序的可观察行为没有改变,他可以把它放在堆栈上; 但这种情况不太可能发生,因为这不会以任何方式使程序的性能受益(并且尚未编写无意义的相关编译器).


1) [lex.string]/8:

普通字符串文字和UTF-8字符串文字也称为窄字符串文字.窄字符串文字的类型为" n的 数组const char",其中n是下面定义的字符串的大小,并且具有静态存储持续时间(3.7).


Grz*_*ski 6

参考N1570(C11草案)6.4.5/6 字符串文字(强调我的未来):

在转换阶段7中,将值为零的字节或代码附加到由字符串文字或文字产生的每个多字节字符序列.78) 然后使用多字节字符序列初始化静态存储持续时间和长度的数组,该数组足以包含序列.对于字符串文字,数组元素具有类型 char,并使用多字节字符序列的各个字节进行初始化.

这意味着字符串文字具有整个程序执行的生命周期,如6.2.4/3 对象的存储持续时间中所述:

声明标识符的对象,如果没有存储类说明符_Thread_local,并且具有外部或内部链接或使用存储类说明符static,则具有静态存储持续时间.它的生命周期是程序的整个执行,它的存储值只在程序启动之前初始化一次.

编译器不太可能将它们放在堆栈上,因为它的性质(提示:在函数调用之间保留).

请注意,C Standard并未明确禁止在字符串上放置字符串文字.事实上,它甚至没有将这样的术语定义为堆栈或.data部分.这取决于编译器,选择符合标准的任何数据放置.