我如何确定这个 C 结构在 32 位和 64 位系统上都被打包了? “__attribute__((packed))”总是必要的吗?

How can I be sure that this C structure is packed both on 32 bit and 64 bit systems? Is "__attribute__((packed))" always necessary?

我正在尝试构建一个简单的自定义应用层协议,主要携带时间戳和一些其他有用的信息,以便在不同的 Linux 系统之间执行少量网络测量。

在我最初的想法中,就 Linux 系统而言,实施应该在不同平台(x86、ARM 等)之间尽可能地可移植。

为了管理 header,我创建了这个结构:

struct myhdr {
    __u8 reserved; // 1 byte
    __u8 ctrl; // 1 byte
    __u16 id; // 2 bytes
    __u16 seq; // 2 bytes
    __u16 len; // 2 bytes
    struct timeval sendtime; // 8 or 16 bytes
};

之后,一些有效载荷数据可能存在也可能不存在(如果 len=0)。 由于此数据必须通过网络发送,如果我没记错的话,我需要要打包的结构,没有任何对齐填充。

我的疑惑其实是这个算不算已经打包了,主要是因为有struct timeval来携带时间戳。

在32位系统下,struct timeval应该是8个字节。在64位系统下,应该是16字节(刚刚通过打印测试sizeof(struct timeval))。

在 32 位系统下,假设它已经打包是否安全,因为 1+1+2+2+2 字节 = 8 字节,这是 sendtime 的大小?或者在任何情况下都会添加一个填充以使每个字段与最后一个最大的字段对齐?

那么在 64 位系统中最后一个字段是 16 字节会发生什么?我认为结构将不再是 "packed by layout",无论如何(这是正确的吗?)。

添加 __attribute__((packed)) 是否足以确保在为不同平台编译代码时打包结构?有没有更好的解决方案?

如果定义有线协议,则确实需要使用自己的类型。为了安全起见,从 1970 年开始的秒数应该使用 64 位,即使许多 32 位系统仍然使用 32 位计数器。

struct timeval 来自系统 header,基本上可以有任何大小,从 8 个字节开始。我确定那里有 32 位系统,它的大小为 12(64 位 time_t 用于 tv_sec 以避免 Y2038 问题,32 位 long/suseconds_t 对于 tv_usec)。此外,POSIX 仅要求 struct timeval 具有某些成员。某些系统在其系统 header 中具有显式字段,以避免编译器隐式填充,从而导致(假设的)打包行为的进一步差异。

虽然 __attribute__ ((pack)) 不递归应用(因此 sizeof (p->sendtime) 将等于 sizeof (struct timeval),但它仍然会减少整个结构的对齐,包括 sendtime 成员,到 1,因此该成员可能未对齐并且不适合直接与期望 struct timeval *.

的函数一起使用