Array as compound literal [duplicate]

五迷三道 提交于 2019-12-19 03:36:33

问题


In C99 we can use compound literals as unnamed array.

But are this literals constants like for example 100, 'c', 123.4f, etc.

I noticed that I can do:

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

and, I have no compilation error and is guessable that the first element of that unnamed array is modified with 100.

So it seems as array as compound literal are lvalue and not constant value.


回答1:


It is an lvalue, we can see this if we look at the draft C99 standard section 6.5.2.5 Compound literals it says (emphasis mine):

If the type name specifies an array of unknown size, the size is determined by the initializer list as specified in 6.7.8, and the type of the compound literal is that of the completed array type. Otherwise (when the type name specifies an object type), the type of the compound literal is that specified by the type name. In either case, the result is an lvalue.

If you want a const version, later on in the same section it gives the following example:

EXAMPLE 4 A read-only compound literal can be specified through constructions like:

(const float []){1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6}

We can find an explanation of the terminology in this Dr Dobb's article The New C: Compound Literals and says:

Compound literals are not true constants in that the value of the literal might change, as is shown later. This brings us to a bit of terminology. The C99 and C90 Standards [2, 3] use the word “constant” for tokens that represent truly unchangeable values that are impossible to modify in the language. Thus, 10 and 3.14 are an integer decimal constant and a floating constant of type double, respectively. The word “literal” is used for the representation of a value that might not be so constant. For example, early C implementations permitted the values of quoted strings to be modified. C90 and C99 banned the practice by saying that any program than modified a string literal had undefined behavior, which is the Standard’s way of saying it might work, or the program might fail in a mysterious way. [...]




回答2:


As far I remeber you are right, compound literals are lvalues*, you can also take pointer of such literal (which points to its first element):

int *p = (int []){1, 2, 3};
*p = 5; /* modified first element */

It is also possible to apply const qualifier on such compound literal, so elements are read-only:

const int *p = (const int []){1, 2, 3};
*p = 5; /* wrong, violation of `const` qualifier */

*Note this not means it's automatically modifiable lvalue (so it can used as left operand for assignment operator) since it has array type and refering to C99 draft 6.3.2.1 Lvalues, arrays, and function designators:

A modifiable lvalue is an lvalue that does not have array type, [...]




回答3:


Referring to the C11 standard draft N1570:

Section 6.5.2.5p4:

In either case, the result is an lvalue.

An "lvalue" is, roughly, an expression that designates an object -- but it's important to note that not all lvalues are modifiable. A simple example:

const int x = 42;

The name x is an lvalue, but it's not a modifiable lvalue. (Expressions of array type cannot be modifiable lvalues, because you can't assign to an array object, but the elements of an array may be modifiable.)

Paragraph 5 of the same section:

The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

The section describing compound literals doesn't specifically say that whether the unnamed object is modifiable or not. In the absence of such a statement, the object is taken to be modifiable unless the type is const-qualified.

The example in the question:

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

is not particularly useful, since there's no way to refer to the unnamed object after the assignment. But a similar construct can be quite useful. A contrived example:

#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]);
}

As mentioned above, the array has automatic storage duration, which means that if it's created inside a function, it will cease to exist when the function returns. Compound literals are not a replacement for malloc.




回答4:


Compound literals are lvalues and it's elements can be modifiable. You can assign value to it. Even pointer to compound literals are allowed.



来源:https://stackoverflow.com/questions/24739998/array-as-compound-literal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!