【发布时间】:2016-04-17 11:55:53
【问题描述】:
人们通常会将“不可修改”与字面量相关联
char* str = "Hello World!";
*str = 'B'; // Bus Error!
但是,当使用复合文字时,我很快发现它们是完全可修改的(查看生成的机器代码,您会看到它们被压入堆栈):
char* str = (char[]){"Hello World"};
*str = 'B'; // A-Okay!
我正在使用clang-703.0.29 进行编译。这两个示例不应该生成完全相同的机器代码吗?如果复合文字是可修改的,它真的是文字吗?
编辑:一个更短的例子是:
"Hello World"[0] = 'B'; // Bus Error!
(char[]){"Hello World"}[0] = 'B'; // Okay!
【问题讨论】:
-
我什至不确定它是 UB,我从未真正看过官方的 language standard,但它在第 12 点的 6.5.2.5 中说,它说
(char[]){"abc"}旨在可以修改。 -
请注意,上面的示例实际上并未展示 lvalue-literal 行为(更清晰的示例类似于
(int){1} = 2;) - 您的两个 sn-ps 之间的主要区别在于第一个你有一个真正的字符串文字,而在第二个中你用字符串文字初始化一个本地数组 - 如果你只是修改第一个来读取char str[] = ...,你会有相同的行为。 -
@Leushenko 我是吗?在复合文字的情况下,我用指向它的第一个字符的指针初始化
str。当我说char str[] = …时,我初始化了一个不可修改的字符文字并将其内容复制到堆栈上的数组str中。 -
@hgiesel:你说得对,它实际上是一个“匿名对象”。您可以使用
const限定符明确告诉编译器您的意图。请注意,在 C 语言中,程序员有责任不违反此约定。即使对于字符串文字,也不能保证写入将不工作(并且C明确允许将其作为实现扩展)。因此,没有收到错误并不意味着它是已定义的行为。如有疑问,请阅读标准。 -
@hgiesel:没有。1)C 语言甚至不强制使用堆栈(也不是堆,顺便说一句。)并且有些实现不强制。 2)在某处分配了一个对象,加上初始化它的字符串文字。但是应该有相同的对象分配两次吗?您使用字符串的示例不是一个好示例,因为您可以直接使用文字,但仍然是有效的。
标签: c c99 literals lvalue compound-literals