Namespaces
Variants

Compound literals (since C99)

From cppreference.net

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)

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 :
storage-class-specifiers type typeof( type ) ID = { initializer-list } ;
ID est un identifiant unique pour l'ensemble du programme. Un littéral composé fournit un objet sans nom dont la valeur, le type, la durée de stockage et autres propriétés sont telles que données par la syntaxe de définition ci-dessus ; si la durée de stockage est automatique, la durée de vie de l'instance de l'objet sans nom est l'exécution courante du bloc englobant. Si les spécificateurs de classe de stockage contiennent d'autres spécificateurs que constexpr , static , register , ou thread_local , le comportement est indéfini.
(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)