Namespaces
Variants

Compound literals (since C99)

From cppreference.net

Konstruiert ein unbenanntes Objekt eines bestimmten Typs (der eine Struktur, Union oder sogar ein Array-Typ sein kann) direkt an Ort und Stelle.

Inhaltsverzeichnis

Syntax

( Speicherklassenspezifizierer  (optional) (seit C23) Typ ) { Initialisiererliste } (seit C99)
( Speicherklassenspezifizierer  (optional) (seit C23) Typ ) { Initialisiererliste , } (seit C99)
( Speicherklassenspezifizierer  (optional) Typ ) { } (seit C23)

wo

storage-class-specifiers - (seit C23) Eine Liste von Speicherklassenspezifizierern , die nur constexpr , static , register , oder thread_local enthalten kann
type - ein Typname , der einen beliebigen vollständigen Objekttyp oder ein Array unbekannter Größe angibt, aber kein VLA
initializer-list - Liste von Initialisierern, die für die Initialisierung eines Objekts vom Typ type geeignet sind

Erklärung

Der zusammengesetzte Literalausdruck konstruiert ein unbenanntes Objekt des durch type spezifizierten Typs und initialisiert es wie durch initializer-list spezifiziert. Designated initializers sind erlaubt.

Der Typ des zusammengesetzten Literals ist type (außer wenn type ein Array unbekannter Größe ist; seine Größe wird vom initializer-list abgeleitet, wie in array initialization beschrieben).

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

Das unbenannte Objekt, auf das der zusammengesetzte Literal ausgewertet wird, hat eine statische Speicherdauer , wenn der zusammengesetzte Literal im Dateibereich auftritt, und eine automatische Speicherdauer , wenn der zusammengesetzte Literal im Blockbereich auftritt (in diesem Fall endet die Lebensdauer des Objekts am Ende des umschließenden Blocks). (bis C23)
Wenn der zusammengesetzte Literal außerhalb des Rumpfs 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 Speicherklassenspezifizierer (möglicherweise leer), der Typname und die Initialisiererliste, falls vorhanden, so beschaffen sein, dass sie gültige Spezifizierer für eine Objektdefinition im Dateibereich bzw. Blockbereich in der folgenden Form sind:
Speicherklassen-Spezifizierer Typ typeof( Typ ) ID = { Initialisierer-Liste } ;
wobei ID ein Bezeichner ist, der für das gesamte Programm eindeutig ist. Ein zusammengesetzter Literal stellt ein unbenanntes Objekt bereit, dessen Wert, Typ, Speicherdauer und andere Eigenschaften so sind, als wären sie durch die obige Definitionssyntax gegeben; wenn die Speicherdauer 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)

Hinweise

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

(const char []){"abc"} == "abc" // kann 1 oder 0 sein, nicht spezifiziert

Jeder zusammengesetzte Literal erzeugt nur ein einzelnes Objekt in seinem Gültigkeitsbereich:

#include <assert.h>
int main(void)
{
    struct S
    {
        int i;
    }
    *p = 0, *q;
    int j = 0;
again:
    q = p,
    p = &((struct S){ j++ }); // erzeugt ein unbenanntes Objekt vom Typ S,
                              // initialisiert es mit dem zuvor in j
                              // gespeicherten Wert, weist dann die Adresse
                              // dieses unbenannten Objekts dem Zeiger p zu
    if (j < 2)
        goto again; // Hinweis: Bei einer Schleife würde hier der Gültigkeitsbereich enden,
                    // was die Lebensdauer des Compound Literals beenden
                    // und p als hängenden Zeiger hinterlassen würde
    assert(p == q && q->i == 1);
}

Da zusammengesetzte Literale unbenannt sind, kann ein zusammengesetztes Literal nicht auf sich selbst verweisen (eine benannte Struktur kann einen Zeiger auf sich selbst enthalten).

Obwohl die Syntax eines zusammengesetzten Literals ähnlich einer Cast-Operation ist, besteht der wichtige Unterschied darin, dass eine Cast-Operation ein Nicht-Lvalue-Ausdruck ist, während ein zusammengesetztes Literal ein Lvalue ist.

Beispiel

#include <stdio.h>
int *p = (int[]){2, 4}; // erzeugt ein unbenanntes statisches Array vom Typ int[2]
                        // initialisiert das Array mit den Werten {2, 4}
                        // erzeugt einen Zeiger p, der auf das erste Element
                        // des Arrays zeigt
const float *pc = (const float []){1e0, 1e1, 1e2}; // schreibgeschütztes Compound Literal
struct point {double x,y;};
int main(void)
{
    int n = 2, *p = &n;
    p = (int [2]){*p}; // erzeugt ein unbenanntes automatisches Array vom Typ int[2]
                       // initialisiert das erste Element mit dem zuvor in *p
                       // gespeicherten Wert
                       // initialisiert das zweite Element mit null
                       // speichert die Adresse des ersten Elements 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},  // erzeugt zwei structs mit Blockgültigkeit und
        (struct point){.x=3, .y=4}); // ruft drawline1 auf und übergibt sie als Wert
    drawline2(
        &(struct point){.x=1, .y=1},  // erzeugt zwei structs mit Blockgültigkeit und
        &(struct point){.x=3, .y=4}); // ruft drawline2 auf und übergibt ihre Adressen
}
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}

Referenzen

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