在C99中,我们可以将复合文字用作未命名的数组。
但这些文字常量是例如100
,'c'
,123.4f
等。
我注意到我能做到:
((int []) {1,2,3})[0] = 100;
并且,我没有编译错误,并且可以猜测该未命名数组的第一个元素是用100修改的。
因此,似乎复合文字的数组是左值而不是常量值。
答案 0 :(得分:6)
这是一个左值,如果我们查看draft C99 standard部分6.5.2.5
复合文字,我们可以看到它(强调我的) :
如果类型名称指定了未知大小的数组,则大小为 由6.7.8中指定的初始化列表和类型确定 复合文字的是已完成的数组类型。除此以外 (当类型名称指定对象类型时),类型 复合文字是由类型名称指定的。 无论哪种情况, 结果是左值。
如果你想要一个 const 版本,稍后在同一部分中给出了以下示例:
示例4可以通过指定只读复合文字 结构如:
(const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}
我们可以在Dobb博士的文章The New C: Compound Literals中找到对术语的解释并说:
复合文字不是真正的常量,因为它的值 文字可能会改变,如后所示。这给我们带来了一些 术语。 C99和C90标准[2,3]使用“常数”一词 代表真正不可改变的代码的代币 不可能用语言修改。因此,10和3.14是整数 十进制常量和double类型的浮点常量。 单词“literal”用于表示值 可能不会那么恒定。例如,早期的C实现 允许修改引用字符串的值。 C90和C99 通过说任何程序而不是修改字符串来禁止这种做法 字面意思是未定义的行为,这是标准的说法 它可能会起作用,或者程序可能会以神秘的方式失败。 [...]
答案 1 :(得分:1)
到目前为止我记得你是对的,复合文字是左值*,你也可以把这个文字的指针(指向它的第一个元素):
int *p = (int []){1, 2, 3};
*p = 5; /* modified first element */
也可以对此类复合文字应用const
限定符,因此元素是只读的:
const int *p = (const int []){1, 2, 3};
*p = 5; /* wrong, violation of `const` qualifier */
*注意这并不意味着它自动可修改左值(因此它可以用作赋值运算符的左操作数),因为它具有数组类型并引用C99草稿6.3.2.1
Lvalues ,数组和函数指示符:
可修改的左值是一个没有数组类型的左值,[...]
答案 2 :(得分:1)
复合文字是左值,它的元素可以修改。您可以为其指定值。甚至允许指向复合文字的指针。
答案 3 :(得分:1)
参考C11标准草案N1570:
第6.5.2.5p4节:
在任何一种情况下,结果都是左值。
“左值”粗略地是指定对象的表达式 - 但重要的是要注意并非所有左值都是可修改的。一个简单的例子:
const int x = 42;
名称x
是左值,但它不是可修改的左值。 (数组类型的表达式不能是可修改的左值,因为你不能分配给数组对象,但是数组的元素可能是可修改的。)
同一节的第5段:
复合文字的值是未命名对象的值 由初始化列表初始化。如果出现复合文字 在函数体外,该对象具有静态存储 持续时间;否则,它有自动存储持续时间 封闭的块。
描述复合文字的部分没有具体说明未命名的对象是否可修改。在没有这样的陈述的情况下,该对象被认为是可修改的,除非类型为const
- 合格。
问题中的例子:
((int []) {1,2,3})[0] = 100;
不是特别有用,因为在赋值后无法引用未命名的对象。但是类似的构造可能非常有用。一个人为的例子:
#include <stdio.h>
int main(void) {
int *ptr = (int[]){1, 2, 3};
ptr[0] = 100;
printf("%d %d %d\n", ptr[0], ptr[1], ptr[2]);
}
如上所述,数组具有自动存储持续时间,这意味着如果它在函数内部创建,则在函数返回时它将不再存在。复合文字不能替代malloc
。