Pourquoi est-ce valide C

Je suis tombé sur ce code sur reddit . J’aurais pensé que les conversions de type auraient rendu cela invalide.

int a[3] = { { {1, 2}, {3, 4}, 5, 6 }, {7, 8}, {9}, 10 }; 

Sur clang, j’obtiens quelques avertissements sur les éléments excessifs et les accolades dans un initialiseur scalaire. Mais le contenu de a est [1, 7, 9] .

Est-ce vraiment légitime, et si c’est le cas, est-ce que quelqu’un pourrait expliquer ce qui se passe exactement?

Les éléments en excès sont simplement ignorés. Il y a deux parties de l’ initialisation 6.7.8 qui vous intéressent. Premièrement, du paragraphe 17:

Chaque liste d’initialisation entourée d’accolades a un object courant associé. Lorsqu’aucune désignation n’est présente, les sous-objects de l’object en cours sont initialisés dans l’ordre en fonction du type de l’object en cours: éléments de tableau dans l’ordre croissant, membres de la structure dans l’ordre de déclaration et premier membre d’une union.

Celui-ci explique pourquoi vous obtenez 1, 7 et 9 – l’object actuel est défini par ces accolades. Ensuite, pourquoi ne pas se soucier des extras, du paragraphe 20:

… seuls les initialiseurs de la liste sont suffisants pour prendre en compte les éléments ou les membres du sous-agrégat ou le premier membre de l’union contenue; tous les initialiseurs restants sont laissés pour initialiser l’élément ou le membre suivant de l’agrégat dont le sous-agrégat actuel ou l’union contenue est une partie.

  int a[3] = { { {1, 2}, {3, 4}, 5, 6 }, {7, 8}, {9}, 10 }; 

est invalide.

Il est invalide pour les mêmes raisons int b[1] = {1, 2}; est invalide: parce que C99 dit

(C99, 6.7.8p1) “Aucun initialiseur ne doit tenter de fournir une valeur pour un object non contenu dans l’entité initialisée.”

Le dernier élément 10 d’ a initialiseur tente de fournir une valeur pour un object non contenu dans l’entité initialisée.