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

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

问题描述

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

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
",sizeof(c));
}

输出是8",意思是我要打包的56位(7个字节)被打包成8个字节,貌似浪费了一个字节.对编译器如何在内存中放置这些位感到好奇,我尝试将特定值写入 &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)

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 上,会发生以下情况:

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

暂时忘记可移植性,假设您关心一个 CPU、一个编译器和一个运行时环境.为什么VC++不能把这个结构打包成7个字节?它是一个字长的东西吗? 上的 MSDN 文档#pragma pack 表示成员的对齐将位于 n 的倍数 [在我的情况下为 1] 的倍数或成员大小的倍数,以较小者为准."谁能告诉我为什么我得到的大小为 8 而不是 7?

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++ 总是至少分配一个与您用于位域的类型相对应的内存单元.您使用了 unsigned int,这意味着最初分配了一个 unsigned int,当第一个耗尽时分配另一个 unsigned int.没有办法强制 MSVC++ 修剪第二个 unsigned int 的未使用部分.

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.

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

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

为您的位域使用较小的类型(unsigned shortunsigned char)并重新组合位域,以便它们完全填充分配的单元 - 这样您应该能把东西收拾得尽可能紧.

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天全站免登陆