4

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.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
xdevel2000
  • 20,780
  • 41
  • 129
  • 196
  • Just to add: I found no reference in standard (at least in C99 1256 draft) that `100`, `'c'` and `123.4f` are any form of _literals_. These are defined as *integer constant*, _character constant_ (also known as _integer character constant_ to put accent on `int` type) and _floating constant_ respectively. – Grzegorz Szpetkowski Jul 14 '14 at 16:21
  • 1
    Shafik's answer sums that up; in C99, *literal* means lvalue literals, and *constant* means rvalue literals. This is orthogonal to the concept of *read-only* (i.e. `const`) . – M.M Jul 15 '14 at 02:11
  • what is your question? – David Jones Feb 18 '18 at 19:15

4 Answers4

6

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. [...]

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    Why, then, are there named as literals if literals are constant? – xdevel2000 Jul 14 '14 at 15:33
  • 2
    @xdevel2000: literals are not constant (as required for switch cases, for example); they are, maybe, read-only values. Changing a read-only value is Undefined Behaviour: it may work when the moon is full ... – pmg Jul 14 '14 at 15:52
  • lvalue does not necessarily mean _modifiable lvalue_ (formal C standard term). Only that the object persists beyond the expression where it was used. – Lundin Aug 24 '18 at 09:04
1

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, [...]

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
1

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

haccks
  • 104,019
  • 25
  • 176
  • 264
  • lvalue does not necessarily mean _modifiable lvalue_ (formal C standard term). Only that the object persists beyond the expression where it was used. – Lundin Aug 24 '18 at 09:04
  • @Lundin; AFAIK, standard mention lvalue as modifiable except when it talk about arrays. – haccks Aug 24 '18 at 09:10
  • Yeah but it doesn't explicitly mention compound literals. The relevant part would be C17 6.3.2.1: `A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.` To say that this proves that compound literals are read/write is far-fetched. Notably, a compound literal can be an array. – Lundin Aug 24 '18 at 09:13
  • (Reason I ended up stalking this old post is [this fresh duplicate](https://stackoverflow.com/questions/51995222/struct-vs-string-literals-read-only-vs-read-write).) – Lundin Aug 24 '18 at 09:15
  • @Lundin; I can see my mistake now. It was a blunder. The thing is compound literals are unnamed objects and saying it is modifiable doesn't make any sense to me. Because how can you modify an object (put it on the right side of an assignment operator) which is unnamed? What lvalue means here is you can modify it as you modify aggregate type (like arrays where you modify it's element not the array). – haccks Aug 24 '18 at 11:02
  • It doesn't make much sense, but modifying it is a quite possible scenario: `int* ptr = (int[]){ ...}; ptr[n] = ...;`. The question is if this is well-defined behavior. – Lundin Aug 24 '18 at 11:32
  • @Lundin; What I mean by modifiable is that it can be used as left operand of the assignment operator and unary `++` operator can be applied on it. In case of array , it is not modifiable. In case of CL, it doesn't make any sense. What you are saying is possible and standard says about CL that [it is modifiable](https://stackoverflow.com/a/52003012/2455888). – haccks Aug 24 '18 at 11:53
1

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.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • "The section describing compound literals doesn't specifically say that whether the unnamed object is modifiable or not." Is it correct to state that since (refering to C99 `6.3.2.1`) "A modifiable lvalue is an lvalue that does not have array type" that such compound literals are not _modifiable lvalues_ ? I tried to explain this in my answer and I assumed that such literals are effectively treated as array types in that matter. – Grzegorz Szpetkowski Jul 15 '14 at 12:10
  • @GrzegorzSzpetkowski: A compound literal of array type is an lvalue of array type. It's not a *modifiable lvalue*, but the elements of the array object may be modifiable. – Keith Thompson Jul 15 '14 at 14:13
  • "In the absence of such a statement, the object is taken to be modifiable unless the type is const-qualified." How did you come to this conclusion? It seems quite unclear to me. The lack of text saying that a non-const qualified compound literal is a modifiable lvalue could possibly be a standard defect. – Lundin Aug 24 '18 at 09:07
  • @Lundin A compound literal "provides an unnamed object whose value is given by the initializer list". There's nothing to say that that object is not modifiable. The compound literal itself is an lvalue and is not a modifiable lvalue (because it's of array type), but the object that it provides is not `const` qualified and so it can be modified. Similarly, given `int arr[2] = { 10, 20 };`, the name `arr` is not a modifiable lvalue, but the object created by the definition can be modified. – Keith Thompson Aug 24 '18 at 18:45
  • @KeithThompson But a compound literal may as well be a struct or a single variable. `type* ptr = &(type){...}; *ptr = ...;` seems like a possible use-case. Reason I brought this up is there's a similar discussion here: [https://stackoverflow.com/questions/51995222/struct-vs-string-literals-read-only-vs-read-write](https://stackoverflow.com/questions/51995222/struct-vs-string-literals-read-only-vs-read-write). – Lundin Aug 27 '18 at 06:35