Инициализация массива структуры инициализирует все элементы одного элемента, почему?


Зачем кому-то это делать? А еще лучше, как это вообще работает? Я бы предположил, что это каким-то образом создаст массив из трех структур с определенным только первым членом. Я понимаю, что указатель указывает на первый элемент массива, и я вижу, как это может работать, но то, как это определено, сбивает меня с толку! (gcc 4.8.4)

void do_something(const void *);

typedef struct{

int a;
char b;
int c;

} the_data_t;

int main(int argc, char *argv[])
{
   the_data_t my_data[] = {10, 'a', 30};
   do_something((const void *)my_data);
}

void do_something(const void *data)
{
   printf("data a: %dndata b: %cndata c: %dn", ((the_data_t*)data)->a,
      ((the_data_t*)data)->b, ((the_data_t*)data)->c);
}

Вывод

Данные a: 10
данные b: a
данные c: 30

Несмотря на это, я изменил его на это..

int main(int argc, char *argv[])
{
   the_data_t my_data = {10, 'a', 30};
   do_something(&my_data);
}
4 5

4 ответа:

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

Нет, это не так. В основном он создает массив из одного элемента, со всеми элементами intialized.

Цитирование C11, Глава §6.7.9

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

И

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

И

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

В принципе, ваш код должен в идеале выглядеть как

the_data_t my_data[] = {{10, 'a', 30}}; 

Визуализировать инициализацию одного элемента.

Ото, то, что вы ожидали, может быть достигнуто с помощью

 the_data_t my_data[] = {{10}, {'a'}, {30}};

, где он создает массив из 3 элементов, все из которых имеют инициализированную переменную-член a.


Что говорит,

 the_data_t my_data[] = {{10, 'a', 30}};

Является эквивалентно написанию

 the_data_t my_data = {10, 'a', 30};

Кроме части, my_data больше не будет массивом ( но что хорошего в массиве из одного элемента вообще?).

Компилятор обработает

the_data_t my_data[] = {10, 'a', 30};   

Как

the_data_t my_data[1] = {{ 10, 'a', 30 }}; // Though it will raise warning.  

Итак, my_data - это массив одного типа the_data_t.

Это похоже на то, когда двумерный массив объявляется следующим образом

int a[][3] = { 1, 2, 3 }; 

Тогда компилятор будет рассматривать его как

int a[1][3] = { { 1, 2, 3 } }; 

Выведите размер a , и вы получите 12 (Если размер int равен 4 на этой машине).

Это неприлично. GCC даст вам предупреждение за это:

warning: missing braces around initializer
warning: (near initialization for ‘my_data[0]’)

Что он будет делать, так это создавать массив из 1 элемента.

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

$ gcc -Wall test.c 
test.c: In function ‘main’:
test.c:14:25: warning: missing braces around initializer [-Wmissing-braces]
 the_data_t my_data[] = {10, 'a', 30};
                        ^
test.c:14:25: note: (near initialization for ‘my_data’)
$ 

Чтобы исправить это, либо вы можете правильно инициализировать массив как:

the_data_t my_data[] = {{10, 'a', 30}};

Или, как вы показали в посте, вы можете изменить my_data на переменную структуры.

the_data_t my_data = {10, 'a', 30}; // And call do_something as
do_something((const void *)&my_data);