Namensräume
Varianten
Aktionen

Compound Literals (seit C99)

Von cppreference.com
< c‎ | Sprache

Konstruiert ein unbenanntes Objekt vom angegebenen Typ (kann struct, union oder sogar ein Array-Typ sein) an Ort und Stelle.

Inhalt

[bearbeiten] Syntax

( storage-class-specifiers (optional)(seit C23) type ) { initializer-list } (seit C99)
( storage-class-specifiers (optional)(seit C23) type ) { initializer-list , } (seit C99)
( storage-class-specifiers (optional) type ) { } (seit C23)

wobei

storage-class-specifiers - (seit C23) Eine Liste von Speicherklassen-Spezifizierern, die nur constexpr, static, register oder thread_local enthalten kann.
type - ein Typ-Name, der jeden vollständigen Objekttyp oder ein Array unbekannter Größe angibt, aber keine VLA
Initialisiererliste - Liste von Initialisierern, die für die Initialisierung eines Objekts vom Typ type geeignet sind.

[bearbeiten] Erklärung

Der Compound-Literal-Ausdruck konstruiert ein unbenanntes Objekt des durch type angegebenen Typs und initialisiert es wie durch initializer-list angegeben. Bezeichner-Initialisierer werden akzeptiert.

Der Typ des Compound Literals ist type (außer wenn type ein Array unbekannter Größe ist; seine Größe wird aus der initializer-list abgeleitet, wie bei der Array-Initialisierung).

Die Wertkategorie eines Compound Literals ist ein lvalue (seine Adresse kann genommen werden).

Das unbenannte Objekt, zu dem der Compound Literal ausgewertet wird, hat eine statische Speicherklasse, wenn der Compound Literal im Dateibereich auftritt, und eine automatische Speicherklasse, wenn der Compound Literal im Blockbereich auftritt (in diesem Fall endet die Lebensdauer des Objekts am Ende des umschließenden Blocks). (bis C23)
Wenn der Compound Literal außerhalb des Körpers einer Funktion und außerhalb einer Parameterliste ausgewertet wird, ist er dem Dateibereich zugeordnet; andernfalls ist er dem umschließenden Block zugeordnet. Abhängig von dieser Zuordnung müssen die Speicherklassen-Spezifizierer (möglicherweise leer), der Typ-Name und die Initialisierungsliste, falls vorhanden, so beschaffen sein, dass sie gültige Spezifizierer für eine Objektdefinition im Dateibereich oder Blockbereich sind, entsprechend der folgenden Form,
   storage-class-specifiers typeof(type) ID = { initializer-list };
wobei ID ein Bezeichner ist, der für das gesamte Programm eindeutig ist. Ein Compound Literal stellt ein unbenanntes Objekt zur Verfügung, dessen Wert, Typ, Speicherklasse und andere Eigenschaften so sind, als wären sie durch die obige Definitions-Syntax gegeben; wenn die Speicherklasse automatisch ist, ist die Lebensdauer der Instanz des unbenannten Objekts die aktuelle Ausführung des umschließenden Blocks. Wenn die Speicherklassen-Spezifizierer andere Spezifizierer als constexpr, static, register oder thread_local enthalten, ist das Verhalten undefiniert.
(seit C23)

[bearbeiten] Hinweise

Compound Literals von const-qualifizierten Zeichen- oder Weitzeichen-Array-Typen können Speicher mit String-Literalen teilen.

(const char []){"abc"} == "abc" // might be 1 or 0, unspecified

Jeder Compound Literal erzeugt nur ein einziges Objekt in seinem Gültigkeitsbereich.

int f (void)
{
    struct s {int i;} *p = 0, *q;
    int j = 0;
again:
    q = p, p = &((struct s){ j++ });
    if (j < 2) goto again; // note; if a loop were used, it would end scope here,
                           // which would terminate the lifetime of the compound literal
                           // leaving p as a dangling pointer
    return p == q && q->i == 1; // always returns 1
}

Da Compound Literals unbenannt sind, kann sich ein Compound Literal nicht selbst referenzieren (eine benannte Struktur kann einen Zeiger auf sich selbst enthalten).

Obwohl die Syntax eines Compound Literals der eines casts ähnelt, ist die wichtige Unterscheidung, dass ein Cast ein Nicht-lvalue-Ausdruck ist, während ein Compound Literal ein lvalue ist.

[bearbeiten] Beispiel

#include <stdio.h>
 
int *p = (int[]){2, 4}; // creates an unnamed static array of type int[2]
                        // initializes the array to the values {2, 4}
                        // creates pointer p to point at the first element of
                        // the array
const float *pc = (const float []){1e0, 1e1, 1e2}; // read-only compound literal
 
struct point {double x,y;};
 
int main(void)
{
    int n = 2, *p = &n;
    p = (int [2]){*p}; // creates an unnamed automatic array of type int[2]
                       // initializes the first element to the value formerly
                       // held in *p
                       // initializes the second element to zero
                       // stores the address of the first element in p
 
    void drawline1(struct point from, struct point to);
    void drawline2(struct point *from, struct point *to);
    drawline1(
        (struct point){.x=1, .y=1},  // creates two structs with block scope and
        (struct point){.x=3, .y=4}); // calls drawline1, passing them by value
    drawline2(
        &(struct point){.x=1, .y=1},  // creates two structs with block scope and
        &(struct point){.x=3, .y=4}); // calls drawline2, passing their addresses
}
 
void drawline1(struct point from, struct point to)
{
    printf("drawline1: `from` @ %p {%.2f, %.2f}, `to` @ %p {%.2f, %.2f}\n",
        (void*)&from, from.x, from.y, (void*)&to, to.x, to.y);
}
 
void drawline2(struct point *from, struct point *to)
{
    printf("drawline2: `from` @ %p {%.2f, %.2f}, `to` @ %p {%.2f, %.2f}\n",
        (void*)from, from->x, from->y, (void*)to, to->x, to->y);
}

Mögliche Ausgabe

drawline1: `from` @ 0x7ffd24facea0 {1.00, 1.00}, `to` @ 0x7ffd24face90 {3.00, 4.00}
drawline2: `from` @ 0x7ffd24facec0 {1.00, 1.00}, `to` @ 0x7ffd24faced0 {3.00, 4.00}

[bearbeiten] Referenzen

  • C23-Standard (ISO/IEC 9899:2024)
  • 6.5.2.5 Compound literals (p: TBD)
  • C17-Standard (ISO/IEC 9899:2018)
  • 6.5.2.5 Compound literals (p: 61-63)
  • C11-Standard (ISO/IEC 9899:2011)
  • 6.5.2.5 Compound literals (p: 85-87)
  • C99-Standard (ISO/IEC 9899:1999)
  • 6.5.2.5 Compound literals (p: 75-77)