VC ++在打包位域时做什么? [英] What is VC++ doing when packing bitfields?

查看:205
本文介绍了VC ++在打包位域时做什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  #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\\\
,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);
}

可以预见,在x86_64上使用Visual Studio 2010,会发生以下情况:

  * 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] 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

p>

暂时忘记可移植性,假设你关心一个CPU,一个编译器和一个运行时环境。为什么VC ++不能把这个结构打包成7个字节?它是一个字长的东西吗? MSDN文档 #pragma) pack 说一个成员的对齐将在一个边界上,该边界是n的倍数(在我的例子中为1)或成员大小的倍数,以较小者为准。任何人都可以给我一些想法为什么我得到一个sizeof 8而不是7?

解决方案

MSVC ++总是分配至少一个单位内存对应于您用于位字段的类型。你使用 unsigned int ,意味着最初分配一个 unsigned int ,另一个 unsigned int 在第一个用尽时分配。没有办法强制MSVC ++修剪第二个 unsigned int 的未使用部分。



基本上,MSVC ++将 unsigned int 解释为表示对齐要求



为位字段使用较小的类型(无符号short unsigned char )并重新组合位字段,以便它们完全填充分配的单元 - 这样,您应该能够尽可能紧密地包装。


To clarify my question, let's start off with an example program:

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

The output is "8", meaning that the 56 bits (7 bytes) I want to pack are being packed into 8 bytes, seemingly wasting a whole byte. Curious about how the compiler was laying these bits out in memory, I tried writing specific values to &c, e.g.:

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

Predictably, on x86_64 using Visual Studio 2010, the following happens:

*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

etc.

Forget portability for a moment and assume you care about one CPU, one compiler, and one runtime environment. Why can't VC++ pack this structure into 7 bytes? Is it a word-length thing? The MSDN docs on #pragma pack says "the alignment of a member will be on a boundary that is either a multiple of n [1 in my case] or a multiple of the size of the member, whichever is smaller." Can anyone give me some idea of why I get a sizeof 8 and not 7?

解决方案

MSVC++ always allocates at least a unit of memory that corresponds to the type you used for your bit-field. You used unsigned int, meaning that a unsigned int is allocated initially, and another unsigned int is allocated when the first one is exhausted. There's no way to force MSVC++ to trim the unused portion of the second unsigned int.

Basically, MSVC++ interprets your unsigned int as a way to express the alignment requirements for the entire structure.

Use smaller types for your bit-fields (unsigned short and unsigned char) and regroup the bit-fields so that they fill the allocated unit entirely - that way you should be able to pack things as tightly as possible.

这篇关于VC ++在打包位域时做什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆