代码之家  ›  专栏  ›  技术社区  ›  es483

我怎样才能确保这个C结构在32位和64位系统上都是打包的?“_属性__((打包))”总是必需的吗?

  •  2
  • es483  · 技术社区  · 6 年前

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

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

    为了管理标题,我创建了以下结构:

    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
    };
    

    由于这些数据必须通过网络发送,如果我没有错的话,我需要打包结构,而不需要任何对齐填充。

    struct timeval

    在32位系统下, 结构时间值 应该是8字节。在64位系统下,它应该是16个字节(通过打印测试) sizeof(struct timeval) ).

    在32位系统下,由于1+1+2+2+2字节=8字节,即 sendtime

    在64位系统中,最后一个字段是16字节,会发生什么情况?我认为在任何情况下,结构都不会再“按布局打包”(这是正确的吗?)。

    正在添加 __attribute__((packed)) 在为不同的平台编译代码时,是否足够且始终需要确保结构是打包的?有更好的解决方案吗?

    1 回复  |  直到 6 年前
        1
  •  5
  •   Florian Weimer    6 年前

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

    struct timeval 来自系统头,基本上可以有任何大小,从8字节开始。我敢肯定有32位系统的大小是12(64位) time_t tv_sec 为避免Y2038问题,32位 long / suseconds_t 对于 tv_usec 结构时间值 他有一些成员。一些系统在其系统头中有显式字段,以避免编译器进行隐式填充,从而导致(假设的)打包行为的进一步差异。

    __attribute__ ((pack)) 不递归应用(因此 sizeof (p->sendtime) sizeof (struct timeval) sendtime 成员,设置为1,因此该成员可能未对齐,不适合直接使用预期 struct timeval * .