What is VC++ doing when packing bitfields?(打包位域时 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 short
和 unsigned 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++ 在做什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:打包位域时 VC++ 在做什么?
基础教程推荐
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- Windows Media Foundation 录制音频 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 从 std::cin 读取密码 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01