Compound literals (since C99)
Construit un objet non nommé de type spécifié (qui peut être une structure, une union, ou même un type tableau) en place.
Table des matières |
Syntaxe
(
storage-class-specifiers
(optionnel)
(depuis C23)
type
)
{
initializer-list
}
|
(depuis C99) | ||||||||
(
storage-class-specifiers
(optionnel)
(depuis C23)
type
)
{
initializer-list
,
}
|
(depuis C99) | ||||||||
(
storage-class-specifiers
(optionnel)
type
)
{
}
|
(depuis C23) | ||||||||
où
| storage-class-specifiers | - | (depuis C23) Une liste de spécificateurs de classe de stockage qui ne peut contenir que constexpr , static , register , ou thread_local |
| type | - | un nom de type spécifiant n'importe quel type d'objet complet ou un tableau de taille inconnue, mais pas un VLA |
| initializer-list | - | liste d'initialiseurs appropriée pour l'initialisation d'un objet de type |
Explication
L'expression littérale composée construit un objet sans nom du type spécifié par type et l'initialise comme spécifié par initializer-list . Les initialiseurs désignés sont acceptés.
Le type du littéral composé est type (sauf lorsque type est un tableau de taille inconnue ; sa taille est déduite de la initializer-list comme dans l'initialisation de tableau ).
La catégorie de valeur d'un littéral composé est lvalue (son adresse peut être prise).
| L'objet sans nom auquel l'expression littérale composée correspond a une durée de stockage statique si le littéral composé apparaît au niveau de la portée de fichier et une durée de stockage automatique storage duration si le littéral composé apparaît au niveau de la portée de bloc (auquel cas la durée de vie de l'objet se termine à la fin du bloc englobant). | (jusqu'à C23) | |||||||||||||||||||||||
Si le littéral composé est évalué en dehors du corps d'une fonction et en dehors de toute liste de paramètres, il est associé à la portée de fichier ; sinon, il est associé au bloc englobant. En fonction de cette association, les spécificateurs de classe de stockage (éventuellement vides), le nom de type et la liste d'initialisation, le cas échéant, doivent être tels qu'ils constituent des spécificateurs valides pour une définition d'objet respectivement au niveau de la portée de fichier ou de la portée de bloc, sous la forme suivante :
|
(depuis C23) | |||||||||||||||||||||||
Notes
Les littéraux composés de types de tableaux de caractères ou de caractères larges qualifiés const peuvent partager le stockage avec les littéraux de chaîne .
(const char []){"abc"} == "abc" // peut être 1 ou 0, non spécifié
Chaque littéral composé ne crée qu'un seul objet dans sa portée :
#include <assert.h> int main(void) { struct S { int i; } *p = 0, *q; int j = 0; again: q = p, p = &((struct S){ j++ }); // crée un objet anonyme de type S, // l'initialise avec la valeur précédemment // détenue dans j, puis assigne l'adresse // de cet objet anonyme au pointeur p if (j < 2) goto again; // note : si une boucle était utilisée, elle terminerait la portée ici, // ce qui mettrait fin à la durée de vie du littéral composé // laissant p comme un pointeur suspendu assert(p == q && q->i == 1); }
Parce que les littéraux composés sont anonymes, un littéral composé ne peut pas se référencer lui-même (une structure nommée peut inclure un pointeur vers elle-même).
Bien que la syntaxe d'un littéral composé soit similaire à une conversion , la distinction importante est qu'une conversion est une expression non lvalue tandis qu'un littéral composé est un lvalue.
Exemple
#include <stdio.h> int *p = (int[]){2, 4}; // crée un tableau statique sans nom de type int[2] // initialise le tableau avec les valeurs {2, 4} // crée le pointeur p pointant vers le premier élément // du tableau const float *pc = (const float []){1e0, 1e1, 1e2}; // littéral composé en lecture seule struct point {double x,y;}; int main(void) { int n = 2, *p = &n; p = (int [2]){*p}; // crée un tableau automatique sans nom de type int[2] // initialise le premier élément avec la valeur précédemment // contenue dans *p // initialise le deuxième élément à zéro // stocke l'adresse du premier élément dans p void drawline1(struct point from, struct point to); void drawline2(struct point *from, struct point *to); drawline1( (struct point){.x=1, .y=1}, // crée deux structures avec portée de bloc et (struct point){.x=3, .y=4}); // appelle drawline1 en les passant par valeur drawline2( &(struct point){.x=1, .y=1}, // crée deux structures avec portée de bloc et &(struct point){.x=3, .y=4}); // appelle drawline2 en passant leurs adresses } 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); }
Sortie possible :
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}
Références
- Norme C23 (ISO/IEC 9899:2024) :
-
- 6.5.2.5 Littéraux composés (p: 77-80)
- Norme C17 (ISO/CEI 9899:2018):
-
- 6.5.2.5 Littéraux composés (p: 61-63)
- Norme C11 (ISO/CEI 9899:2011) :
-
- 6.5.2.5 Littéraux composés (p: 85-87)
- Norme C99 (ISO/CEI 9899:1999) :
-
- 6.5.2.5 Littéraux composés (p: 75-77)