Since c99 compound literals can be used to e.g. initialize pointers:
int *p = (int []) {1, 2, 3, 4};
while this is usually used for structs it can be used to initialize anonymous arrays as well (see example). But if I understood this correctly initializing a scalar pointer like this:
int *p = &(int) {4};
is also valid. What I find confusing is the statement on the gcc site that “Compound literals for scalar types and union types are also allowed, but then the compound literal is equivalent to a cast.” Do they simply mean that using the address-of operator & in front of an anonymous scalar is a form of casting?
By definition a compound literal does not consist of & address-of operator. From N1570 6.5.2.5/p3 Compound literals:
A postfix expression that consists of a parenthesized type name
followed by a brace-enclosed list of initializers is a compound
literal.
Now, their statement:
Compound literals for scalar types and union types are also allowed,
but then the compound literal is equivalent to a cast.
is rather wrong if I am reading it correctly. The fundamental difference between compound literal and cast operator is that the former is a lvalue, as by N1570 6.5.2.5/p4 (emphasis mine):
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.
while the latter is not, 6.5.4/p5 Cast operators (emphasis mine):
Preceding an expression by a parenthesized type name converts the
value of the expression to the named type. This construction is called
a cast.104)
104) A cast does not yield an lvalue. Thus, a cast to a qualified type
has the same effect as a cast to theunqualified version of the type.
Related
The section 6.5.2.5/4 provides an explanation about the postfix-expression of the form ( type-name ) { initializer-list }. Here it is:
If the type name specifies an array of unknown size, the size is
determined by the initializer list as specified in 6.7.9, 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.
I don't understand the wording the type of the compound literal. How is it even possible for a literal to have a type? Does the type of the corresponding unnamed object is meant by the type of the compound literal?
For instance
long long *longs = (long long []) {1333, 3123, 3, 122};
The initializer-list here is used to initialize an unnamed object of type long long [4].
Also it is not clear what is the purpose of In either case, the result is an lvalue. When using in an assignment-expression the lvalue conversion is performed on the right operand so it is no longer an lvalue.
Presumably, a "compound literal" means the object/value that a use of the "compound literal" language construct designates. Values/objects have types in C.
The purpose of making compound literals lvalues is so that code like
int *x = &(int){42}; *x = 43; works. It makes compound literals behave kind of like anonymous variables. (Not completely, though. Unlike regular variables, compound literals can't have storage class specifiers, which I personally consider a language defect.)
The main purpose of compound literal is to provide an anonymous object, so you can have a pointer to an real object without creating a variable first.
It's an lvalue, which means that one may obtain it address. But, it's not modifiable lvalue though, just like an ordinary array object:
int a[] = {0, 0};
a = {1, 2}; // error, a is not a modifiable lvalue
But of course, you can modify it by using subscript operator or indirect pointer access:
a[0] = 1; // fine
(long long []) {1333, 3123, 3, 122}[0] = 1; // fine as well
Is a const compound literal a valid initializer for a static variable?
#define COMPOUND ((const int [2]){1, 2})
static const int x = COMPOUND[0];
/* static const int x = 1; should be equivalent */
EDIT:
The possible duplicacte in the first comment doesn't make sense, because I'm asking explicitly about const literals, and not variables.
Yes, an element of a compound literal may be used as an initializer.
C 2018 6.7.9 4 tells us what initializers must be:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
6.6 tells us what constant expressions may be. Paragraph 3 says:
Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.
Paragraph 4 says:
Each constant expression shall evaluate to a constant that is in the range of representable values for its type.
Paragraph 7 expands this to:
More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
an arithmetic constant expression,
a null pointer constant,
an address constant, or
an address constant for a complete object type plus or minus an integer constant expression.
None of the other paragraphs prohibit the use of compound literals, so they are permitted.
Using C99 I'm trying to do this within a function:
foo_t foos[4];
foos[0] = {1, {1,2}};
doesn't work. So I tried this...
foo_t foos[4];
foos[0] = (foo_t){1, {1,2}};
which works, but is it safe? Is there not perhaps a better way to do this?
The first case failed, because there no type associated with the expression (brace enclosed initializer)
Yes, the second code is safe, as long as the initializer list matches the expected types for the LHS. This is called compound literal, FWIW.
Quoting C11, chapter §6.5.2.5
A postfix expression that consists of a parenthesized type name followed by a brace enclosed
list of initializers is a compound literal. It provides an unnamed object whose value is given by the initializer list.
The following program prints the same number twice on gcc 4.8.2:
#include <stdio.h>
int main()
{
char a[13];
printf("sizeof a is %zu\n", sizeof a );
printf("sizeof(a) is %zu\n", sizeof(a));
}
According to this reddit post, gcc is not standard-conformant in this respect, because a parenthesized expression is not on the list of exceptions for when array-to-pointer decay does not happen.
Is this guy correct? Here is the relevant standard quote:
Except when it is the operand of the sizeof operator or the unary & operator, or is a character string literal used to initialize an array of character type, or is a wide string literal used to initialize an array with element type compatible with wchar_t, an lvalue that has type 'array of type' is converted to an expression that has type 'pointer to type' that points to the initial member of the array object and is not an lvalue.
Just to be clear, he argues that (a) should trigger array-to-pointer decay, because parentheses are not covered in the list above (sizeof operator, unary & operator, string literal as initializer).
Whether seemingly redundant parentheses affect the semantics of a program is a long-standing issue in the C standard that still hasn't been adequately resolved.
It is commonly claimed that ((void*)0) is technically not a null pointer constant, because there is no rule that says a parenthesised null pointer constant is a null pointer constant.
Some compilers issue an error for char s[] = ("abc");, because while a character array can be initialised from a string literal, that rule doesn't cover parenthesised string literals.
There are many similar examples. You've found one of them.
From what I can tell, the concensus is basically that the rule should be what C++ does, but what C never formally adopted. C++ makes a parenthesised expression functionally equivalent to the non-parenthesised expression, with a few explicitly-stated exceptions. This would cover all those issues at once.
So technically, the guy could be considered correct, but it's an overly strict interpretation of the standard that nobody really follows, since it's common knowledge that the standard is simply faulty here.
From C99, 6.5.1, on parenthesized expressions:
Its type and value are identical to those of the unparenthesized expression.
At first glance, it would appear that this conflicts with the exception list you're referring to (6.3.2.1):
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type"...
However, this list is in the context of operators/operands; parentheses don't appear to be deemed an operator (based on the categorisation implied by the structure of section 6.5).
This question already has answers here:
Why are compound literals in C modifiable
(2 answers)
Closed 4 years ago.
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.
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. [...]
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, [...]
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.
Compound literals are lvalues and it's elements can be modifiable. You can assign value to it. Even pointer to compound literals are allowed.