2016-08-11 2 views
5

Зачем кому-то это делать? Еще лучше, как это работает? Я бы предположил, что это каким-то образом создаст массив из трех структур с только определенным первым членом. Я понимаю, что указатель указывает на первый элемент массива, и я вижу, как это может работать, но как это определено, отбрасывает меня! (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: %d\ndata b: %c\ndata c: %d\n", ((the_data_t*)data)->a, 
     ((the_data_t*)data)->b, ((the_data_t*)data)->c); 
} 

Выход

данные А: 10
данные B:
данные с: 30

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

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

Вы должны показать реальный код. Может быть, вспомогательная функция предназначена для работы с массивами.Поэтому, если массив содержит хотя бы один элемент, вы должны объявить его как массив, а не одну структуру. –

+2

Невозможно инициализировать только часть структуры, это все или ничего. – molbdnilo

ответ

8

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

Нет, это не так. По сути, он создает массив из одного элемента, причем все члены инициализируются.

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

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

и

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

и

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

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

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 не будет массив больше (но что хороший массив один элемент, в общем, либо?).

+1

«Что хорошего в массиве одного элемента, в общем,» -> Он позволяет передавать код «ссылкой» [пример GMP] (https://gmplib.org/list-archives/gmp-discuss/2008-March /003085.html) Исследовать, как объявляется 'mpz_t'. – chux

+0

Этот ответ, по сути, правильный, но было бы намного яснее, если бы он также процитировал C2011 6.7.9/20, в котором явно описывается семантика для случая, когда нет скобок вокруг инициализатора члена, как это наблюдается здесь. –

+0

@JohnBollinger обновлен, если это помогает. –

2

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

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

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

+0

GCC предупреждает, и я согласен с ним, и с вами, что опускание фигурных скобок вокруг инициализаторов членов плохое. Но это все * все. Код совершенно правильный в том смысле, что он соответствует стандарту. –

3

Компилятор будет относиться к

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 на этой машине).

+0

Очевидно, что конкретный компилятор, используемый *, * интерпретирует инициализатор, как вы описываете, но мне трудно понять, как это поведение описывается стандартом. –

+0

@JohnBollinger; Это описано в разделе ** 6.7.9/20 **: * Если инициализатор субагрегата или содержащегося объединения начинается с левой скобки, инициализаторы, заключенные в эту скобку, и ее подходящая правая скобка инициализируют элементы или элементы суммирования или объединенный союз. В противном случае только достаточное количество инициализаторов из списка учитывается для элементов или членов субагрегата или первого члена объединенного союза; любые оставшиеся инициализаторы оставляют для инициализации следующего элемента или члена совокупности, из которых текущий субагрегат или [...]. * – haccks

2

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); 
Смежные вопросы