liveBook · Manning

Compound literal

As explained in Modern C, Third Edition

A compound literal is C syntax consisting of a type name in parentheses followed by an initializer that creates an unnamed object with the specified type and value.

A compound literal has the form `(T){ INIT }`: a type in parentheses followed by an initializer. It defines an unnamed object of type `T`; it is not merely a value written in a different notation. For example, `(size_t){ 3 }` defines a `size_t` object initialized to 3. section 5.6.4

# define CORVID_NAME /**/         \
(char const*const[corvid_num]){    \
  [chough] = "chough",            \
  [raven] = "raven",              \
  [magpie] = "magpie",            \
  [jay] = "jay",                  \
}

This macro replaces its name with an array compound literal. The initializer supplies names at designated indices, so an expression such as `CORVID_NAME[i]` can select one. The space before the compound literal prevents the macro from being parsed as function-like. section 5.6.4

TAKEAWAY: A compound literal defines an object, not an integer constant expression. When a macro is intended to behave like a named constant, qualify its type with `const`, but do not assume that makes it suitable wherever a compile-time constant is required. Macro definitions are text replacement: omit a terminating semicolon from the replacement. section 5.6.4

Check a macro argument's type

The pattern `((T){ (X) })` initializes a temporary object of type `T` from `X`. Unlike a cast, initialization requires `X` to be assignment-compatible with `T`. With `T` as `void*`, this can check a pointer argument before it is printed with `%p`; a cast would suppress the intended type check. An optimizing compiler can remove the temporary object's runtime cost. section 17.2

An address taken from a compound literal must not outlive its object:

  • In a `while` body, each iteration defines a new local instance. A pointer assigned `&(size_t){ fun() }` there cannot validly dereference that object after the loop. section 19.3
  • A repeated statement reached by `goto` can instead leave the object alive until the surrounding block ends. The pointer can remain usable, but the object retains resources longer. section 19.3

C23 also permits `constexpr` on a compound literal. This supplies a compile-time-checked constant for uses such as an initializer at file scope; its initializer must fit exactly, and `const` qualification is implied. section 5.6.5

How Modern C, Third Edition covers it

How deep it goes
Defines the syntax and object semantics, then works through macro pitfalls, initialization checks, and contrasting local-object lifetimes.
Examples
Uses an array-of-names macro, a pointer-printing argument check, and while-versus-goto lifetime snippets.
What it assumes
Builds on C types, initializers, arrays, pointers, and macros while defining compound-literal syntax explicitly.
What you can do after
Build it from scratch: write typed compound literals for macros and argument checks while avoiding invalid access after an object's lifetime.
How it connects
Connects compound literals to initializers, macros, assignment compatibility, object lifetime, integer constant expressions, and constexpr.

Also explained in

Compare how 2 books explain compound literal →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C, Third Edition. The section links point to the parts of the book it draws on.