Compound literals (since C99)
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:
|
(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)