[英]Union data structure alignment
我正在使用一些(我认为是)具有联合的坏代码:
union my_msg_union
{
struct message5;
char buffer[256]
} message;
缓冲区中有来自通信的256个字节。 结构类似于:
struct message5 {
uint8 id;
uint16 size;
uint32 data;
uint8 num_ids;
uint16 ids[4];
} message5d
在大量架构(8位AVR,16位菲利普斯,32位臂,32位x86和amd64)上编译相同的代码。
我认为的问题是使用了union:代码只是一串连续接收到缓冲区的字节,然后通过struct读取值,而不考虑struct的对齐/填充。
果然,快速查看不同系统上的sizeof(message5d)给出了不同的结果。
然而令我感到惊讶的是,每当与char []的联合存在时,所有类型的所有结构的所有实例在所有系统上都会丢弃它们的填充/对齐,并确保是连续的字节。
这是C标准还是编译器作者为“帮助”提供的东西?
此代码演示了与您描述的相反的行为:
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
struct message5
{
uint8_t id;
uint16_t size;
uint32_t data;
uint8_t num_ids;
uint16_t ids[4];
};
#if !defined(NO_UNION)
union my_msg_union
{
struct message5 msg;
char buffer[256];
};
#endif /* NO_UNION */
struct data
{
char const *name;
size_t offset;
};
int main(void)
{
struct data offsets[] =
{
{ "message5.id", offsetof(struct message5, id) },
{ "message5.size", offsetof(struct message5, size) },
{ "message5.data", offsetof(struct message5, data) },
{ "message5.num_ids", offsetof(struct message5, num_ids) },
{ "message5.ids", offsetof(struct message5, ids) },
#if !defined(NO_UNION)
{ "my_msg_union.msg.id", offsetof(union my_msg_union, msg.id) },
{ "my_msg_union.msg.size", offsetof(union my_msg_union, msg.size) },
{ "my_msg_union.msg.data", offsetof(union my_msg_union, msg.data) },
{ "my_msg_union.msg.num_ids", offsetof(union my_msg_union, msg.num_ids) },
{ "my_msg_union.msg.ids", offsetof(union my_msg_union, msg.ids) },
#endif /* NO_UNION */
};
enum { NUM_OFFSETS = sizeof(offsets) / sizeof(offsets[0]) };
for (size_t i = 0; i < NUM_OFFSETS; i++)
printf("%-25s %3zu\n", offsets[i].name, offsets[i].offset);
return 0;
}
示例输出(Mac OS X 10.9 Mavericks上的GCC 4.8.2,64位编译):
message5.id 0
message5.size 2
message5.data 4
message5.num_ids 8
message5.ids 10
my_msg_union.msg.id 0
my_msg_union.msg.size 2
my_msg_union.msg.data 4
my_msg_union.msg.num_ids 8
my_msg_union.msg.ids 10
联合中的偏移量与结构中的偏移量相同,如C标准所要求的那样。
你必须根据上面的代码给出一个完整的编译反例 - 并指定你正在编译的编译器和平台来获得你的偏差答案 - 如果你确实可以重现不正确的答案。
我注意到我必须将uint8
等更改为uint8_t
,但我认为这没有任何区别。 如果是,您需要指定从uint8
获取名称的标题。
更新的代码可以在有或没有union
情况下编译。 使用-DNO_UNION
编译时的-DNO_UNION
:
message5.id 0
message5.size 2
message5.data 4
message5.num_ids 8
message5.ids 10
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.