尝试将数据打包到数据包中。该数据包应为64位。我有这个:
typedef union {
uint64_t raw;
struct {
unsigned int magic : 8;
unsigned int parity : 1;
unsigned int stype : 8;
unsigned int sid : 8;
unsigned int mlength : 31;
unsigned int message : 8;
} spacket;
} packet_t;
但似乎无法保证对齐。因为当我运行时:
#include <strings.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
const char *number_to_binary(uint64_t x)
{
static char b[65];
b[64] = '\0';
uint64_t z;
int w = 0;
for (z = 1; w < 64; z <<= 1, ++w)
{
b[w] = ((x & z) == z) ? '1' : '0';
}
return b;
}
int main(void)
{
packet_t ipacket;
bzero(&ipacket, sizeof(packet_t));
ipacket.spacket.magic = 255;
printf("%s\n", number_to_binary(ipacket.raw));
ipacket.spacket.parity = 1;
printf("%s\n", number_to_binary(ipacket.raw));
ipacket.spacket.stype = 255;
printf("%s\n", number_to_binary(ipacket.raw));
ipacket.spacket.sid = 255;
printf("%s\n", number_to_binary(ipacket.raw));
ipacket.spacket.mlength = 2147483647;
printf("%s\n", number_to_binary(ipacket.raw));
ipacket.spacket.message = 255;
printf("%s\n", number_to_binary(ipacket.raw));
}
我得到(大端):
1111111100000000000000000000000000000000000000000000000000000000
1111111110000000000000000000000000000000000000000000000000000000
1111111111111111100000000000000000000000000000000000000000000000
1111111111111111111111111000000000000000000000000000000000000000
1111111111111111111111111000000011111111111111111111111111111110
1111111111111111111111111000000011111111111111111111111111111110
我的.mlength
字段在右侧部分丢失,但它应该在.sid
字段旁边。
This page确认它:&#34;包含位字段&#34;的分配单元的对齐方式。但如果是这种情况,那么人们如何将数据打包到比特字段中,这首先是他们的目的呢?
24位似乎是.mlength
字段在.message
字段被踢出之前可以采取的最大大小。
答案 0 :(得分:1)
关于位字段布局的几乎所有内容都是在标准中实现定义的,正如您从SO上的许多其他问题中找到的那样。 (除其他外,您可以查看Questions about bitfields,尤其是Bit field's memory management in C)。
如果希望将位字段打包为64位,则必须相信编译器允许您对字段使用64位类型,然后使用:
typedef union {
uint64_t raw;
struct {
uint64_t magic : 8;
uint64_t parity : 1;
uint64_t stype : 8;
uint64_t sid : 8;
uint64_t mlength : 31;
uint64_t message : 8;
} spacket;
} packet_t;
正如最初编写的,在一种似是而非(通用)的方案下,当当前的空间不足够剩余空间时,您的位字段将被拆分为新的32位字。也就是说,magic
,parity
,stype
和sid
将占用25位;在32位unsigned int
中没有足够的空间来容纳另外31位,因此mlength
存储在下一个unsigned int
中,并且没有足够的空间留在该单元存储message
,以便存储在第三个unsigned int
单元中。这将为您提供占用3 * sizeof(unsigned int)
或12个字节的结构 - 由于uint64_t
上的对齐要求,并集将占用16个字节。
请注意,该标准并不保证我展示的内容会起作用。但是,在许多编译器下,它可能会起作用。 (具体来说,它适用于Mac OS X 10.11.4上的GCC 5.3.0。)
答案 1 :(得分:0)
根据您的体系结构和/或编译器,您的数据将与不同的大小对齐。根据你的观察,我猜你会看到32位对齐的后果。如果你看一下你的联合的大小,并且超过8个字节(64位)的数据已被填充以进行对齐。
对于32位对齐mlength,如果它们总和小于或等于32位,则消息将只能保持彼此相邻。这可能就是你所看到的24位限制。
如果你希望你的结构只采用64位32位对齐,你将不得不重新排列它。单比特奇偶校验应该在31比特mlength的旁边,并且你的4个8比特变量应该组合在一起。