数组为复合文字

时间:2014-07-14 15:21:51

标签: c c99 compound-literals

在C99中,我们可以将复合文字用作未命名的数组。

但这些文字常量是例如100'c'123.4f等。

我注意到我能做到:

((int []) {1,2,3})[0] = 100;

并且,我没有编译错误,并且可以猜测该未命名数组的第一个元素是用100修改的。

因此,似乎复合文字的数组是左值而不是常量值。

4 个答案:

答案 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