2017-02-10 14 views
1

Допустим, у меня есть тип структуры:Initializing одну структуру с содержанием другой структуры

typedef struct 
{ 
    int a; 
    int b[3]; 
    int c; 
} __attribute__((packed)) foo_t; 

И я инициализировать таким образом:

foo_t first = { 1, { 2, 3, 4 }, 5 }; 

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

typedef struct 
{ 
    int b[3]; 
    int c; 
} __attribute__((packed)) bar_t; 

bar_t second = { first.b[3], first.c }; //this should define first.c as 5 
memcpy(second.b, first.b, 3 * sizeof(int)); 

Если напечатать значения каждой переменной в second массив b определяется правильно, но c всего 0.

printf("%d %d %d %d\n", second.b[0], second.b[1], second.b[2], second.c); 

выходы

2 3 4 0 

Почему не second.c получить заселена правильно?

ответ

0

Ответил на мой вопрос буквально через несколько секунд после публикации этого.

Чтобы инициализировать содержимое новой структуры массивом, вы должны поместить фигурные скобки вокруг части массива. Кроме того, указание first.b[3] в качестве значения инициализации фактически захватит 4-й элемент 3-элементного массива, который является неопределенным и плохим кодом. {0} может использоваться в качестве заполнителя для любого массива произвольного размера, пока memcpy не будет использоваться на следующей строке. Таким образом, правильный фрагмент кода должен выглядеть следующим образом:

typedef struct 
{ 
    int b[3]; 
    int c; 
}__attribute__((packed)) bar_t; 

bar_t second = { {0}, first.c}; //this should define first.c as 5 
memcpy(second.b,first.b,3*sizeof(int)); 
+0

.., который все еще оставляет вопрос о том, какое значение 'first.b [3]' как 'b' имеет только три элемента и вы копируете четвертый элемент. Обратите внимание, что инициализатор является значением, а не определением. –

+0

Да, хороший момент. Я понимаю, о чем вы говорите. Что я мог бы заменить 'first.b [3]' в этом контексте, чтобы выступать в качестве «держателя места», пока не сделаю memcpy на следующей строке? Обратите внимание, что в реальном коде, над которым я работаю, массив большой, поэтому явным образом набираю '{first.b [0], first.b [1], first.b [2], first.b [3], first.b [4] .... etc} 'будет несостоятельным. –

+1

Я считаю, что в инициализаторе все элементы, не упомянутые специально, равны нулю, поэтому '{{0}, first.c}' должен делать трюк. Пожалуйста, проверьте его. –

0

Что касается технического обслуживания кода, используя memcpy() копировать части структуры к другой другого типа, является проблематичным: что произойдет, если один (но не оба) из модифицированы типы структуры?

Поэтому я предлагаю использовать

typedef struct 
{ 
    int b[3]; 
    int c; 
} __attribute__ ((__packed__)) bar; 

typedef struct 
{ 
    int a; 
    bar bar; 
} __attribute__ ((__packed__)) foo; 

Тогда, имея

foo first = {1, {2, 3, 4}, 5}; 
bar second; 

вы можете явно сделать

second = foo.bar; 

Лично я хотел бы предложить, добавив аксессоры макросы тоже :

#define BAR_B(var, index) ((var).b[index]) 
#define BAR_C(var)  ((var).c) 

#define FOO_A(var)  ((var).a) 
#define FOO_B(var, index) ((var).bar.b[index]) 
#define FOO_C(var)  ((var).bar.c) 

, который может использоваться как как lvalues, так и rvalues ​​(т. любая сторона в заданиях). Это упрощает обслуживание, если вам необходимо повторно разбить или изменить структуру содержимого позже; вам тогда не нужно менять сам код, только модифицируйте макросы доступа.

0

В вашем определении first.c анализируется как инициализатор для второго ввода second.b, который сразу же перезаписывается memcpy. Кстати, first.b[3] является недействительным доступом за пределами first.b.

Для того, чтобы second.c быть инициализирован со значением first.c инициализатором следует переписать в виде:

bar_t second = { { 0 } , first.c}; 
memcpy(second.b, first.b, sizeof(second.b)); 

Вы также можете избавиться от memcpy инициализации second.b элементов в явном виде:

bar_t second = { { first.b[0], first.b[1], first.b[2] }, first.c}; 

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