为什么C中的复合文字可以修改

hgi*_*sel 10 c c99 literals compound-literals lvalue

人们通常将"不可修改的"与术语"文字"联系起来

char* str = "Hello World!";
*str = 'B';  // Bus Error!
Run Code Online (Sandbox Code Playgroud)

然而,当使用复合文字时,我很快发现它们是完全可修改的(并且锁定在生成的机器代码上,你会看到它们被推到堆栈上):

char* str = (char[]){"Hello World"};
*str = 'B';  // A-Okay!
Run Code Online (Sandbox Code Playgroud)

我正在编译clang-703.0.29.这两个例子不应该生成完全相同的机器代码吗?如果它是可修改的,复合文字真的是文字吗?

编辑:一个更短的例子是:

"Hello World"[0] = 'B';  // Bus Error!
(char[]){"Hello World"}[0] = 'B';  // Okay!
Run Code Online (Sandbox Code Playgroud)

hac*_*cks 11

复合文字是左值,其元素的值是可修改的.的情况下

char* str = (char[]){"Hello World"};
*str = 'B';  // A-Okay!  
Run Code Online (Sandbox Code Playgroud)

你正在修改合法的复合文字.

C11-§6.5.2.5/ 4:

如果类型名称指定了未知大小的数组,则大小由6.7.9中指定的初始化程序列表确定,复合文字的类型是已完成数组类型的类型.否则(当类型名称指定对象类型时),复合文字的类型是由类型名称指定的类型.在任何一种情况下,结果都是左值.

可以看出复合文字的类型是一个完整的数组类型并且是左值,因此它可以修改,不像字符串文字

标准也提到了

§6.5.2.5/ 7:

字符串文字和具有const限定类型的复合文字不需要指定不同的对象.101

进一步说:

11示例4可以通过以下结构指定只读复合文字:

(const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}   
Run Code Online (Sandbox Code Playgroud)

12例5以下三个表达方式有不同的含义:

"/tmp/fileXXXXXX"
(char []){"/tmp/fileXXXXXX"}
(const char []){"/tmp/fileXXXXXX"}
Run Code Online (Sandbox Code Playgroud)

第一个总是具有静态存储持续时间并且具有类型数组char,但不需要可修改 ; 当它们出现在函数体内时,最后两个具有自动存储持续时间,并且这两个中第一个是可修改的.

13示例6与字符串文字一样,const限定的复合文字可以放入只读内存中,甚至可以共享.例如,

(const char []){"abc"} == "abc"
Run Code Online (Sandbox Code Playgroud)

如果文字的存储是共享的,则可能会产生1.