我们说我有一个结构类型:
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 :(得分:0)
在发布此内容后几秒钟回答了我自己的问题。
为了使用数组初始化新结构的内容,必须在数组部分周围放置大括号。此外,将first.b[3]
指定为初始化值实际上将获取3元素数组的第4个元素,这是未定义的和错误的代码。 {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));
答案 1 :(得分: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)
可以用作左值和右值(即任务中的任一侧)。它使维护更容易,以防您以后需要重新拆分或重新排列结构内容;然后,您不需要更改代码本身,只需修改访问者宏。
答案 2 :(得分: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))
在您的声明中不可移植且无用,因为所有类型都相同。除非绝对必要,否则请避免使用此类内容。