数组为复合文字

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

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

我注意到我能做到:

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

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

所以它似乎作为复合文字的数组是左值而不是常量值。

这是一个左值,我们可以看到这个,如果我们看看草案C99标准部分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禁止这种做法,他说任何程序都比未修改的字符串文字具有未定义的行为,这是标准说它可能有效的方式,或者程序可能以神秘的方式失败。 […]

到目前为止,我记得你是对的,复合文字是左值*,你也可以得到这样的文字指针(指向它的第一个元素):

 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 左值,数组和函数指示符

可修改的左值是一个没有数组类型的左值,[…]

参考C11标准草案N1570 :

第6.5.2.5p4节:

在任何一种情况下,结果都是左值。

“左值”大致是指定对象的表达式 – 但重要的是要注意并非所有左值都是可修改的。 一个简单的例子:

 const int x = 42; 

名称x是左值,但它不是可修改的左值。 (数组类型的表达式不能是可修改的左值,因为您无法分配给数组对象,但数组的元素可能是可修改的。)

同一节第5段:

复合文字的值是初始化列表初始化的未命名对象的值。 如果复合文字出现在函数体外,则该对象具有静态存储持续时间; 否则,它具有与封闭块相关的自动存储持续时间。

描述复合文字的部分没有具体说明未命名的对象是否可修改。 在没有这样的陈述的情况下,除非该类型是合格的,否则该对象被认为是可修改的。

问题中的例子:

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

并不是特别有用,因为在赋值后无法引用未命名的对象。 但是类似的构造可能非常有用。 一个人为的例子:

 #include  int main(void) { int *ptr = (int[]){1, 2, 3}; ptr[0] = 100; printf("%d %d %d\n", ptr[0], ptr[1], ptr[2]); } 

如上所述,数组具有自动存储持续时间,这意味着如果它在函数内部创建,则在函数返回时它将不再存在。 复合文字不是malloc的替代品。

复合文字是左值,它的元素可以修改。 您可以为其指定值。 甚至允许指向复合文字的指针。