Are Compound Literals Standard C++

Are compound literals Standard C++?

This is an extension that both gcc and clang support. The gcc document says:

As an extension, GCC supports compound literals in C90 mode and in C++, though the semantics are somewhat different in C++.

if you build with -pedantic you should receive a warning, for example clang says (see it live):

warning: compound literals are a C99-specific feature [-Wc99-extensions]

Note, the semantic differences in C++ are not minor and code that would be well-defined in C99 can have undefined behavior in C++ with this extension:

In C++, a compound literal designates a temporary object, which only
lives until the end of its full-expression. As a result, well-defined
C code that takes the address of a subobject of a compound literal can
be undefined in C++.

Why are compound literals not part of C++ so far?

I think that there is no need for compound literals in C++, because in some way, this functionality is already covered by its OOP capabilities (objects, constructors and so on).

You program may be simply rewritten in C++ as:

#include <cstdio>

struct Point
{
Point(int x, int y) : x(x), y(y) {}
int x, y;
};

void printPoint(Point p)
{
std::printf("%d, %d", p.x, p.y);
}

int main()
{
printPoint(Point(2, 3)); // passing an anonymous object
}

is a compound literal not a literal?

The C11 standard never defines "literal" on its own. It only speaks of "string literal" and "compound literal" individually.

Tokens such as 0, 0.0, the A in enum { A }, and '\0' are called "constants" collectively, and "integer constants", "floating-point constants", "enumeration constants", and "character constants" respectively.

Why are compound literals in C modifiable

A compound literal is an lvalue and values of its elements are modifiable. In case of

char* str = (char[]){"Hello World"};
*str = 'B'; // A-Okay!

you are modifying a compound literal which is legal.

C11-§6.5.2.5/4:

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.

As it can be seen that the type of compound literal is a complete array type and is lvalue, therefore it is modifiable unlike string literals

Standard also mention that

§6.5.2.5/7:

String literals, and compound literals with const-qualified types, need not designate distinct objects.101

Further it says:

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

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

12 EXAMPLE 5 The following three expressions have different meanings:

"/tmp/fileXXXXXX"
(char []){"/tmp/fileXXXXXX"}
(const char []){"/tmp/fileXXXXXX"}

The first always has static storage duration and has type array of char, but need not be modifiable; the last two have automatic storage duration when they occur within the body of a function, and the first of these
two is modifiable
.

13 EXAMPLE 6 Like string literals, const-qualified compound literals can be placed into read-only memory and can even be shared. For example,

(const char []){"abc"} == "abc"

might yield 1 if the literals’ storage is shared.

Compound literals in MSVC

The construct (Type){initialisers} is not a cast operation, but it is the syntactic construct of a compound literal.
This is a C99 construct, which GCC also supports in its C++ compiler as an extension. As far as I can determine, compound literals are not supported up to and including MSVC 2012, in either its C or C++ mode. The support in C mode was introduced later, in MSVC 2013. In C++ mode it is still not supported and I believe it is unlikely support will be added.

For MSVC 2012 and older, the alternatives for this construct are

  • Explicitly declare and initialise a temporary object of the desired struct type and use that instead of the compound literal in the assignment
  • Instead of doing a single assignment with the compound literal, use a separate assignment for each individual member.

Compound literals and function-like macros: bug in gcc or the C standard?

This "bug" has existed in the standard since C89:

#include <stdio.h>

void function(int a) {
printf("%d\n", a);
}

#define macro(a) do { printf("%d\n", a); } while (0)

int main() {
function(1 ? 1, 2: 3); /* comma operator */
macro(1 ? 1, 2: 3); /* macro argument separator - invalid code */
return 0;
}

I haven't actually looked through the standard to check this parse, I've taken gcc's word for it, but informally the need for a matching : to each ? trumps both operator precedence and argument list syntax to make the first statement work. No such luck with the second.

What is the lifetime of compound literals passed as arguments?

It's valid C in C99 or above.

C99 §6.5.2.5 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.

In your example, the compound literal has automatic storage, which means, its lifetime is within its block, i.e, the main() function that it's in.

Recommended reading from @Shafik Yaghmour:

  1. The New C: Compound Literals
  2. GCC Manual: 6.25 Compound Literals


Related Topics



Leave a reply



Submit