我如何确定在32位和64位系统上都打包有此C结构?是否总是需要“ __attribute __((packed))”?

时间:2019-01-13 17:00:01

标签: c gcc struct attributes packed

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

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

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

FileResponse

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

我的疑问是,实际上是否可以考虑是否已经打包(主要是由于def printPDF(request): response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename=hello.pdf' p = canvas.Canvas(response) p.drawString(100, 100, "Hello world.") p.showPage() p.save() return response 来携带时间戳)。

在32位系统中,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 }; 应该是8个字节。在64位系统下,它应该为16字节(通过打印struct timeval进行测试)。

在32位系统下,由于1 + 1 + 2 + 2 + 2字节= 8字节(即struct timeval的大小)是否可以安全地假定已经打包?还是在任何情况下都将添加填充以使每个字段与最后一个字段对齐(最后一个字段最大)?

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

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

1 个答案:

答案 0 :(得分:4)

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

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

尽管struct timeval并不是递归适用的(因此__attribute__ ((pack))将等于sizeof (p->sendtime),但它仍将包括sizeof (struct timeval)成员在内的整个结构的对齐方式减少为1 ,因此该成员可能会错位且不适合直接与期望sendtime的函数一起使用。