Почему это действительно C

Я наткнулся на этот код на reddit. Я бы подумал, что преобразования типов приведут к тому, что это будет недействительным.

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

В clang я получаю несколько предупреждений о чрезмерных элементах и ​​фигурных скобках в скалярном инициализаторе. Но содержимое a равно [1, 7, 9].

Это действительно законно, и если да, может кто-нибудь объяснить, что именно происходит?

Ответ 1

Элементы избытка просто игнорируются. Есть две части 6.7.8 Инициализация, о которой вы заботитесь. Во-первых, из пункта 17:

Каждый список инициализаторов, заключенный в фигурные скобки, имеет связанный с ним текущий объект. Когда обозначений нет, подобъекты текущего объекта инициализируются в порядке, соответствующем типу текущего объекта: элементы массива в возрастающем порядке индекса, члены структуры в порядке объявления и первый именованный член объединения.

В этом объясняется, почему вы получаете 1, 7 и 9 - текущий объект устанавливается этими фигурными скобками. Затем, почему он не заботится о дополнительных вещах, из параграфа 20:

... только достаточное количество инициализаторов из списка учитывается для элементов или членов субагрегата или первого члена объединенного союза; любые оставшиеся инициализаторы оставляют для инициализации следующего элемента или члена совокупности, частью которого является текущий субагрегат или содержащий объединение.

Ответ 2

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

неверно.

Недействительно по тем же причинам int b[1] = {1, 2}; является недопустимым: поскольку C99 говорит

(C99, 6.7.8p1) "Ни один инициализатор не попытается предоставить значение для объекта, не содержащегося в инициализированном объекте".

Последний элемент 10 в a инициализаторы пытаются предоставить значение для объекта, не содержащегося в инициализированном объекте.