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.
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
I have encountered a strange behaviour when using compound literals for static struct initialization in GCC in c99/gnu99 modes.
Apparently this is fine:
struct Test
{
int a;
};
static struct Test tt = {1}; /* 1 */
However, this is not:
static struct Test tt = (struct Test) {1}; /* 2 */
This triggers following error:
initializer element is not constant
Also this does not help either:
static struct Test tt = (const struct Test) {1}; /* 3 */
I do understand that initializer value for a static struct should be a compile-time constant. But I do not understand why this simplest initializer expression is not considered constant anymore? Is this defined by the standard?
The reason I'm asking is that I have encountered some legacy code written in GCC in gnu90 mode, that used such compound literal construct for static struct initialization (2). Apparently this was a GNU extension at the time, which was later adopted by C99.
And now it results in that the code that successfully compiled with GNU90 cannot be compiled with neither C99, nor even GNU99.
Why would they do this to me?
This is/was a gcc bug (HT to cremno), the bug report says:
I believe we should just allow initializing objects with static
storage duration with compound literals even in gnu99/gnu11. [...]
(But warn with -pedantic.)
We can see from the gcc document on compound literals that initialization of objects with static storage duration should be supported as an extension:
As a GNU extension, GCC allows initialization of objects with static
storage duration by compound literals (which is not possible in ISO
C99, because the initializer is not a constant).
This is fixed in gcc 5.2. So, in gcc 5.2 you will only get this warning when using the -pedantic flag see it live, which does not complain without -pedantic.
Using -pedantic means that gcc should provide diagnostics as the standard requires:
to obtain all the diagnostics required by the standard, you should
also specify -pedantic (or -pedantic-errors if you want them to be
errors rather than warnings)
A compound literal is not a constant expression as covered by the C99 draft standard section 6.6 Constant expressions, we see from section 6.7.8 Initialization that:
All the expressions in an initializer for an object that has static storage duration shall be
constant expressions or string literals.
gcc is allowed to accept other forms of constant expressions as an extension, from section 6.6:
An implementation may accept other forms of constant expressions.
interesting to note that clang does not complain about this using -pedantic
C language relies on an exact definition of what is constant expression. Just because something looks "known at compile time" does not mean that it satisfies the formal definition of constant expression.
C language does not define the constant expressions of non-scalar types. It allows implementations to introduce their own kinds of constant expressions, but the one defined by the standard are restricted to scalar types only.
In other words, C language does not define the concept of constant expression for your type struct Test. Any value of struct Test is not a constant. Your compound literal (struct Test) {1} is not a constant (and is not a string literal) and, for this reason, it cannot be used as an initializer for objects with static storage duration. Adding a const qualifier to it will not change anything since in C const qualifier has no relation whatsoever to the concept of constant expression. It will never make any difference in such contexts.
Note that your first variant does not involve a compound literal at all. It uses a raw { ... } initializer syntax with constant expressions inside. This is explicitly allowed for objects with static storage duration.
So, in the most restrictive sense, the initialization with a compound literal is illegal, while the initialization with ordinary { ... } initializer is fine. Some compilers might accept compound literal initialization as an extension. (By extending the concept of constant expression or by taking some other extension path. Consult compiler documentation to figure out why it compiles.)
Interestingly, the clang does not complain with this code, even with -pedantic-errors flag.
This is most certainly about C11 §6.7.9/p4 Initialization (emphasis mine going forward)
All the expressions in an initializer for an object that has static or
thread storage duration shall be constant expressions or string
literals.
Another subclause to look into is §6.5.2.5/p5 Compound literals:
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.
and (for completeness) §6.5.2.5/p4:
In either case, the result is an lvalue.
but this does not mean, that such unnamed object can be treated as constant expression. The §6.6 Constant expressions says inter alia:
2) A constant expression can be evaluated during translation rather
than runtime, and accordingly may be used in any place that a constant
may be.
3) 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.
10) An implementation may accept other forms of constant expressions.
There is no explicit mention about compound literals though, thus I would interpret this, they are invalid as constant expressions in strictly conforming program (thus I'd say, that clang has a bug).
Section J.2 Undefined behavior (informative) also clarifies that:
A constant expression in an initializer is not, or does not 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
(6.6).
Again, no mention about compound literals.
Neverthless, there is a light in the tunnel. Another way, that is fully sanitized is to convey such unnamed object as address constant. The standard states in §6.6/p9 that:
An address constant is a null pointer, a pointer to an lvalue
designating an object of static storage duration, or a pointer to a
function designator; it shall be created explicitly using the unary &
operator or an integer constant cast to pointer type, or implicitly by
the use of an expression of array or function type. The
array-subscript [] and member-access . and -> operators, the address &
and indirection * unary operators, and pointer casts may be used in
the creation of an address constant, but the value of an object shall
not be accessed by use of these operators.
hence you can safely initialize it with constant expression in this form, because such compound literal indeed designates an lvalue of object, that has static storage duration:
#include <stdio.h>
struct Test
{
int a;
};
static struct Test *tt = &((struct Test) {1}); /* 2 */
int main(void)
{
printf("%d\n", tt->a);
return 0;
}
As checked it compiles fine with -std=c99 -pedantic-errors flags on both gcc 5.2.0 and clang 3.6.
Note, that as opposite to C++, in C the const qualifier has no effect on constant expressions.
ISO C99 does support compound literals (according to this). However, currently only the GNU extension provides for initialization of objects with static storage duration by compound literals, but only for C90 and C++.
A compound literal looks like a cast containing an initializer. Its value is an object of the type specified in the cast, containing the elements specified in the initializer; it is an lvalue. As an extension, GCC supports compound literals in C90 mode and in C++, though the semantics are somewhat different in C++.
Usually, the specified type is a structure. Assume that struct foo and structure are declared as shown:
struct foo {int a; char b[2];} structure;
Here is an example of constructing a struct foo with a compound literal:
structure = ((struct foo) {x + y, 'a', 0});
This is equivalent to writing the following:
{
struct foo temp = {x + y, 'a', 0};
structure = temp;
}
GCC Extension:
As a GNU extension, GCC allows initialization of objects with static storage duration by compound literals ( which is not possible in ISO C99, because the initializer is not a constant ). It is handled as if the object is initialized only with the bracket enclosed list if the types of the compound literal and the object match. The initializer list of the compound literal must be constant. If the object being initialized has array type of unknown size, the size is determined by compound literal size.
static struct foo x = (struct foo) {1, 'a', 'b'};
static int y[] = (int []) {1, 2, 3};
static int z[] = (int [3]) {1};
Note:
The compiler tags on your post include only GCC; however, you make comparisons to C99, (and multiple GCC versions). It is important to note that GCC is quicker to add extended capabilities to its compilers than the larger C standard groups are. This has sometimes lead to buggy behavior and inconsistencies between versions. Also important to note, extensions to a well known and popular compiler, but that do not comply with an accepted C standard, lead to potentially non-portable code. It is always worth considering target customers when deciding to use an extension that has not yet been accepted by the larger C working groups/standards organizations. (See ISO (Wikipedia) and ANSI (Wikipedia).)
There are several examples where the smaller more nimble Open Source C working groups or committees have responded to user base expressed interest by adding extensions. For example, the switch case range extension.
Quoting the C11 standard, chapter §6.5.2.5, Compound literals, paragraph 3, (emphasis mine)
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.
So, a compound literal is tread as an unnamed object, which is not considered a compile time constant.
Just like you cannot use another variable to initialize a static variable, onward C99, you cannot use this compound literal either to initialize a static variable anymore.
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.
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.
I was very surprised when I saw this notation. What does it do and what kind of C notion is it?
This is a compound literal as defined in section 6.5.2.5 of the C99 standard.
It's not part of the C++ language, so it's not surprising that C++ compilers don't compile it. (or Java or Ada compilers for that matter)
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.
So no, it won't destroy the stack. The compiler allocates storage for the object.
Parenthesis are put around the type and it is then followed by an initializer list - it's not a cast, as a bare initialiser list has no meaning in C99 syntax; instead, it is a postfix operator applied to a type which yields an object of the given type. You are not creating { 0, 3 } and casting it to an array, you're initialising an int[2] with the values 0 and 3.
As to why it's used, I can't see a good reason for it in your single line, although it might be that a could be reassigned to point at some other array, and so it's a shorter way of doing the first two lines of:
int default_a[] = { 0, 2 };
int *a = default_a;
if (some_test) a = get_another_array();
I've found it useful for passing temporary unions to functions
// fills an array of unions with a value
kin_array_fill ( array, ( kin_variant_t ) { .ref = value } )
This is a c99 construct, called a compound literal.
From the May 2005 committee draft section 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.
...
EXAMPLE 1 The file scope definition
int *p = (int []){2, 4};
initializes p
to point to the first element of an
array of two ints, the first having
the value two and the second, four.
The expressions in this compound
literal are required to be constant.
The unnamed object has static storage
duration.
Allocates, on the stack, space for [an array of] two ints.
Populates [the array of] the two ints with the values 0 and 2, respectively.
Declares a local variable of type int* and assigns to that variable the address of [the array of] the two ints.
(int[2]) tells the compiler that the following expression should be casted to int[2]. This is required since {0, 2} can be casted to different types, like long[2]. Cast occurs at compile time - not runtime.
The entire expression creates an array in memory and sets a to point to this array.
{0, 2} is the notation for an array consisting of 0 and 2.
(int[2]) casts it to an array (don't know why).
int * a = assigns it to the int pointer a.