Array as a composite literal

In C99, we can use compound literals as an unnamed array.

But are these literal constants, 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 we can assume that the first element of this unnamed array changes to 100.

Thus, an array, as a composite literal, has an lvalue value, not a constant value.

+3
c c99
source share
4 answers

This is an lvalue, we can see it if we look at the draft of the C99 project 6.5.2.5 Component literals that it says (emphasis mine):

If the type name indicates an array of unknown size, the size determined by the list of initializers, as specified in 6.7.8, and the type of the composite literal is the type of the completed array. Otherwise (when the type name indicates the type of the object), the type composite literal is the name indicated by the type. In any case, the result is an lvalue.

If you want a version of const, later in the same section, you will get the following example:

EXAMPLE 4 A read-only binding literal can be specified through constructs like:

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

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

Component literals are not true constants in the sense that the value of a Literal can change, as shown below. This leads us to the terminology. Standards C99 and C90 [2, 3] use the word โ€œconstantโ€ for tokens, which are truly immutable values โ€‹โ€‹that cannot be changed in the language. Thus, 10 and 3.14 are integers, a decimal constant and a floating constant of type double, respectively. The word literal is used to represent a meaning that may not be so constant. For example, early implementations of C are allowed to change the values โ€‹โ€‹of quoted strings. C90 and C99 banned the practice, stating that any program that changed the literal line had undefined behavior, which is the standard way of saying this might work, or the program might fail in a mysterious way. [...]

+4
source share

As far as I remember, you are right, complex literals are lvalues โ€‹โ€‹*, you can also take a pointer to such a literal (which points to its first element):

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

You can also apply the const qualifier in such a composite literal, so the elements are read-only:

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

* Note: this does not mean that it automatically changes the value of lvalue (therefore, it can be used as the left operand for the assignment operator), since it has an array type and refers to a draft C99 6.3.2.1 Lvalues, arrays and function pointers:

The lvalue modifiable value is an l value that does not have an array type, [...]

+1
source share

Compound literals are l-value. You can assign a value to it. Even a pointer to complex literals is allowed.

+1
source share

Referring to the standard project C11 N1570 :

Section 6.5.2.5p4:

In any case, the result is an lvalue.

An "lvalue" is, roughly speaking, an expression that denotes an object, but it is important to note that not all lvalues โ€‹โ€‹are modifiable. A simple example:

 const int x = 42; 

The name x is an lvalue, but it is not a mutable value of an lvalue. (Array type expressions cannot be modifiable lvalues โ€‹โ€‹because you cannot assign an array object, but array elements can be modifiable.)

Point 5 of the same section:

Compound literal value - This is the name of an unnamed object that is initialized with a list of initializers. If a composite literal is outside the function body, the object has a static storage duration; otherwise, it has an automatic storage duration associated with the closing unit.

The section describing compound literals does not specifically state whether an unnamed object is modifiable or not. In the absence of such a statement, an object is considered modifiable if the type is const -qualified.

Example in question:

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

not particularly useful as there is no way to refer to an unnamed object after assignment. But a similar design can be very 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, an array has an automatic storage duration, which means that if it is created inside a function, it will cease to exist when the function returns. Component literals do not replace malloc .

+1
source share

All Articles