Инициализация массива структуры инициализирует все элементы одного элемента, почему?
Зачем кому-то это делать? А еще лучше, как это вообще работает? Я бы предположил, что это каким-то образом создаст массив из трех структур с определенным только первым членом. Я понимаю, что указатель указывает на первый элемент массива, и я вижу, как это может работать, но то, как это определено, сбивает меня с толку! (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 ответа:
я бы предположил, что это каким-то образом создаст массив из трех структур с только первым членом, определенным
Нет, это не так. В основном он создает массив из одного элемента, со всеми элементами 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);