为了澄清我的问题,让我们从一个示例程序开始:

#include <stdio.h>

#pragma pack(push,1)
struct cc {
    unsigned int a   :  3;  
    unsigned int b   : 16;
    unsigned int c   :  1;
    unsigned int d   :  1;
    unsigned int e   :  1;
    unsigned int f   :  1;
    unsigned int g   :  1;
    unsigned int h   :  1;
    unsigned int i   :  6;  
    unsigned int j   :  6;  
    unsigned int k   :  4;  
    unsigned int l   : 15;
};
#pragma pack(pop)

struct cc c;

int main(int argc, char **argv)

{   printf("%d\n",sizeof(c));
}

输出为“ 8”,这意味着我想打包的56位(7个字节)被包装到8个字节中,似乎浪费了整个字节。对编译器如何将这些位放在内存中的方式感到好奇,我尝试将特定值写入 &c, ,例如:

int main(int argc,char ** argv)

{
unsigned long long int* pint = &c;
*pint = 0xFFFFFFFF;
printf("c.a = %d", c.a);
...
printf("c.l = %d", c.l);
}

可以预见的是,在使用Visual Studio 2010的X86_64上,发生以下情况:

*pint = 0x00000000 000000FF :

c[0].a = 7
c[0].b = 1
c[0].c = 1
c[0].d = 1
c[0].e = 1
c[0].f = 1
c[0].g = 0
c[0].h = 0
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0

*pint = 0x00000000 0000FF00 :

c[0].a = 0
c[0].b = 0
c[0].c = 0
c[0].d = 0
c[0].e = 0
c[0].f = 0
c[0].g = 1
c[0].h = 127
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0


*pint = 0x00000000 00FF0000 :

c[0].a = 0
c[0].b = 0
c[0].c = 0
c[0].d = 0
c[0].e = 0
c[0].f = 0
c[0].g = 0
c[0].h = 32640
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0

等等

暂时忘记便携性,假设您关心一个CPU,一个编译器和一个运行时环境。 VC ++为什么不能将此结构包装到7个字节中?这是一个长篇小说吗?这 MSDN文档#pragma pack 说:“成员的比对将处于n [1]的倍数或成员大小的倍数,以较小者为准。”谁能给我一些想法,为什么我要获得8个尺寸,而不是7个?

有帮助吗?

解决方案

MSVC ++总是至少分配一个与您用于位场的类型相对应的内存单元。你用了 unsigned int, ,这意味着一个 unsigned int 最初是分配的,另一个是 unsigned int 当第一个精疲力尽时分配。无法强制MSVC ++修剪第二个未使用的部分 unsigned int.

基本上,MSVC ++解释您的 unsigned int 作为表达的一种方式 对齐要求 用于整个结构。

使用较小的类型在您的位场(unsigned shortunsigned char)并重新组合位场,以便它们完全填充分配的单元 - 这样您就应该能够尽可能紧紧打包东西。

其他提示

Bitfields存储在您定义的类型中。因为您正在使用 unsigned int, ,并且它不适合一个 unsigned int 然后,编译器必须使用第二个整数并将最后24位存储在最后一个整数中。

好吧,您正在使用未签名的int,在这种情况下恰好是32位。未签名的INT的下一个边界(适合Bitfield)为64位=> 8个字节。

PST是正确的。这 成员 在1字节边界(或较小,因为它是一个比特菲尔德)上对齐。整体结构具有8尺寸,并在8字节边界处对齐。这符合标准和 pack 选项。文档永远不会说最后没有填充。

要给另一个有趣的说明说明发生了什么,请考虑要包装越过类型边界的结构的情况。例如

struct state {
    unsigned int cost     : 24; 
    unsigned int back     : 21; 
    unsigned int a        :  1; 
    unsigned int b        :  1; 
    unsigned int c        :  1;
};

据我所知,这种结构不能使用MSVC包装到6个字节中。但是,我们可以通过分解前两个字段来获得所需的包装效果:

struct state_packed {
    unsigned short cost_1   : 16; 
    unsigned char  cost_2   :  8;
    unsigned short back_1   : 16; 
    unsigned char  back_2   :  5;
    unsigned char  a        :  1; 
    unsigned char  b        :  1; 
    unsigned char  c        :  1; 
};

这确实可以包装成6个字节。但是,访问原始成本字段非常尴尬和丑陋。一种方法是将态度的指针施放为专业的虚拟结构:

struct state_cost {
    unsigned int cost     : 24;
    unsigned int junk     :  8; 
};

state_packed    sc;
state_packed *p_sc = &sc;

sc.a = 1;
(*(struct state_cost *)p_sc).cost = 12345;
sc.b = 1;

如果有人知道这样做的更优雅的方式,我很想知道!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top