现象
struct Test
{
UINT32 test1 :4;
UINT32 test2 :2;
UINT32 test3 :4;
UINT32 test4 :3;
UINT32 test5 :4;
UINT32 test6 :3;
UINT32 test7 :4;
UINT32 test8 :2;
};
今日于底层发现如上代码,头一次见到这种“:x”代码,不知何意,写了些代码测试出该如何使用。
过程
1.首先将其结构增加构造函数如下
struct Test
{
UINT32 test1 :4;
UINT32 test2 :2;
UINT32 test3 :4;
UINT32 test4 :3;
UINT32 test5 :4;
UINT32 test6 :3;
UINT32 test7 :4;
UINT32 test8 :2;
Test()
{
test1 = 0;
test2 = 0;
test3 = 0;
test4 = 0;
test5 = 0;
test6 = 0;
test7 = 0;
test8 = 0;
}
};
2.sizeof(Test)的值为4;
3.声明一个Test变量,查看内存显示为 00 00 00 cc,说明只初始化了4字节中的头三个字节,依据这个现象,猜测:x中的x是比字节更小的单位,即比特。可以先按照比特来猜测某些操作的结果,如果不成立的话再想另外的可能性。
4.给变量赋值
Test test;
test.test1 = 1; // 01 00 00 cc
test.test2 = 2; // 21 00 00 cc
test.test3 = 3; // e1 00 00 cc
来分析下每一步操作都干了什么事情:
1)声明变量; 内存为00 00 00 cc 二进制为:0000 0000 0000 0000 0000 0000 1100 1100
2)test.test1 = 1;二进制:1 内存为01 00 00 cc 二进制为:0000 0001 0000 0000 0000 0000 1100 1100
3)test.test2 = 2;二进制:10 内存为21 00 00 cc 二进制为:0010 0001 0000 0000 0000 0000 1100 1100
4)test.test3 = 3;二进制:11 内存为e1 00 00 cc 二进制为:1110 0001 0000 0000 0000 0000 1100 1100
现在很明显:x的x就是这个变量占据的比特位数
5)test.test4 = 4;二进制:100 内存为e1 10 00 cc 二进制为:1110 0001 0001 0000 0000 0000 1100 1100
6)test.test8 = 8;二进制:1000 内存为e1 10 00 cc 二进制为:1110 0001 0001 0000 0000 0000 1100 1100
test8只能占2bit,高位被截断,所以相当于将00赋值给test8
5.内存对齐问题:
struct Test1
{
__int64 test1 :30;
UINT32 test2 :2;
}; //sizeof(Test1)为16
1)内存对齐的规则和一般对象的变量相同,只不过:x强制制定了该变量多少位有效,高位的数据统统截断;
2)是否可以使用该方法使某些类型占的大小变大呢?
struct Test1
{
__int64 test1 :30;
UINT32 test2 :2;
char test3 :64;
};
以上代码在编译时就报错:error C2034: “Test1::test3”: 位域类型对位数太小。看来是不可以了。
疑问?
1.为什么会出现这种用法?
在使用上,由于某种原因,在业务范围内,Test对象的各个变量都有最大值,这种写法一个对象占4个字节,而按照普通写法一个对象占用8×sizeof(int)=32字节;
由于不了解汇编,不清楚在使用一个对象时是如何读取内存的。也就不能确定在Windows上这种做法是否效率更高。
猜测,公司有做硬件,也许对于专门优化过的(有这种优化么?)硬件来说,尽量小的存储空间和传输通道会效率更高?
2.从上学到现在各种语言也略微看过些,从来就没有发现这种语法,网上也没有查到什么资料,这到底是从哪个石头缝里蹦出来的语法?