位域是指在信息存储时候并不需要一个完整的字节,只需要占用一个或几个二进制位。
例如:存放一个开关量的时候,只有0和1两种状态,用一位二进制位表示就行了。
所谓位域,就是把一个字节(8位)中的二进制位分为几个不同的区域,并说明几个区域的位数.
需要注意的是:
1,位域的类型必须是整型或枚举类型。
2,一个位域字段必须小于等于一个字节(8位). 如果当前字节所剩下的空间不足以存储下一个位域字段指定的位域的时候,从下一个字节开始存储接着存储.我们也可以手动指出从下一个直接开始存储.
3,取地址操作符不能用到位域字段上。
4,位域字段不能是类的静态成员.
5,位域字段在内存中的位置是按照从低位到高位的顺序放置的(针对intel CPU也就是little-endian).
6,别的CPU可能是按照big-endian放置数据到位域字段中的。
7,(wiki)https://en.wikipedia.org/wiki/Endianness
#include <iostream>
#include <iostream>
//intel: little-endian
class BitField { //BitField中的a,b,c,d,e表示位域字段.
private:
unsigned int a : 4; //最低位 // 0<= a <= 15;
unsigned int b : 3; // 0<= b <= 7;
unsigned int c : 1; // 0<= c <=1;
unsigned int d : 4; // 0<= d <= 15;
unsigned int e : 4; //最高位 // 0<= e <=15;
unsigned int f : 2; // 0<= f <=3;
unsigned int : 0; //这里指出即使当前字节没有存满,也会从下一个字节开始存储.
unsigned int g : 8; // 0<= g <=255
public:
BitField();
~BitField()=default;
void setBit();
void print()const noexcept;
};
BitField::BitField()
/*:a(1)
b(2)
c(1)
d(3) //不能这么初始化.
e(4) */
{
//
}
void BitField::setBit()
{
this->a = 1;
this->b = 1;
this->c = 1;
this->d = 1;
this->e = 1;
this->f = 1;
this->g = 1;
}
void BitField::print()const noexcept
{
std::cout << this->a << " "
<< this->b << " "
<< this->c << " "
<< this->d << " "
<< this->e << " "
<< this->f << " "
<< this->g << std::endl;
}
int main()
{
BitField f;
f.setBit();
f.print();
return 0;
}
位域的内存对齐:
1,如果相邻位域字段的类型相同,且位宽之和的大小 小于该类型sizeof的大小,则后面的位域将紧邻前面位域名存储,直到该字节已经不能容纳为止.
2,如果相邻位域字段的类型相同,且位宽之和的大小 大于该类型的sizeof的大小,则后面的位域将开辟一个新的字节进行存储.
3,如果相邻的位域字段的类型不相同,是否采取压缩方式要看编译器了。
4,如果位域字段之间穿插着非位域的字段,则不采用压缩。
5,整个位域结构体的sizeof大小,为结构体内最宽类型成员的整数倍.
Demo 1:
//测试工具: vs2015, x64模式.
//intel: little-endian
struct BF {
unsigned char a1 : 5;
unsigned char a2 : 5;
unsigned char a3 : 5;
unsigned char a4 : 5;
unsigned char a5 : 5;
};
int main()
{
//输出: 1(字节)
std::cout << "unsigned char: " << sizeof(unsigned char) << std::endl;
//输出: 4(字节)
std::cout << "BF: " << sizeof(BF) << std::endl;
//BF中的位域表面上是一共占用了25个二进制位,不够4个字节,但是又多于3个字节
//这样一来编译器就会自动填充位,足够4个字节.
return 0;
}
Demo 2:
//测试工具: vs2015, x86
//intel: little-endian
struct BF {
unsigned char a1 : 5;
unsigned char a2 : 5;
long int a3 : 5; //注意这里的long int类型.
unsigned int a4 : 5;
unsigned char a5 : 5;
};
int main()
{
//输出: 1(字节)
std::cout << "unsigned char: " << sizeof(unsigned char) << std::endl;
//输出: 4(字节)
std::cout << "long int: " << sizeof(long int) << std::endl;
//输出: 12(字节)
std::cout << "BF: " << sizeof(BF) << std::endl;
//a1 和 a2只占了10位不够2个字节,但是a3是个long int 类型是4个字节
//a1 和 a2就会补位到4个字节以便于和 a3对齐.到这里就4个字节了.
//a3占了4个字节,到这里就8个字节了.
//a4 和 a5占用了10位不够2个字节补位到与long int的位数相同也就是4个字节,到这里就占用了12个字节了.
return 0;
}