复合字面量是可被赋值的左值,在其元素的值可修改。在以下情况下,
char* str = (char[]){"Hello World"};
*str = 'B'; // A-Okay!
您正在修改一个合法的复合字面值。
C11-§6.5.2.5/4:
如果类型名称指定了未知大小的数组,则大小由初始化列表指定,复合字面值的类型为完成的数组类型。否则(当类型名称指定对象类型时),复合字面量的类型是由类型名称指定的。 在任何情况下,结果都是lvalue。
正如可以看到的那样,复合字面值的类型是一个完整的数组类型,并且是lvalue,因此与字符串字面值不同,它是可修改的。
标准还提到:
§6.5.2.5/7:
字符串文字和带有const限定类型的复合文字不需要指定不同的对象。101
此外,它说:
11 EXAMPLE 4 可以通过以下结构指定只读复合字面量:
(const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
12例5:下列三个表达式有不同的含义:
"/tmp/fileXXXXXX"
(char []){"/tmp/fileXXXXXX"}
(const char []){"/tmp/fileXXXXXX"}
第一个对象始终具有静态存储期,并且具有char
数组类型,但不需要是可修改的; 当它们出现在函数体内时,后两个对象具有自动存储期,并且这两个对象中的第一个对象是可修改的。
13 示例6 像字符串字面值一样,带const限定符的复合字面值可以放置在只读内存中,甚至可以共享。例如,
(const char []){"abc"} == "abc"
如果字面值的存储被共享,可能会产生1。
(char[]){"abc"}
被设计为可修改的。 - hgiesel(int){1} = 2;
的东西)-你两个片段之间的主要区别在于第一个中有一个真正的字符串字面量,而在第二个中你使用一个字符串字面量初始化了一个本地数组 -如果你只是修改第一个来读取char str[] = ...
,你将会得到相同的行为。 - Alex Celestestr
。当我说char str[] = …
时,我初始化了一个不可修改的 char 字面量,并将其内容复制到堆栈上的数组str
中。 - hgieselconst
修饰符来明确告诉编译器你的意图。需要注意的是,在C语言中,不破坏这个约定是程序员的责任。即使对于字符串字面值,也不能保证写入操作不起作用(并且C明确允许这种实现扩展)。所以,不出现错误并不意味着这是定义良好的行为。如果有疑问,请阅读标准文档。 - too honest for this sitechar str[] = (char[]){"Hello"};
时,我是否实际上在堆栈上初始化了两次。 - hgiesel