有关联合体嵌套结构体 、位域(位段)、小端存放

普通嵌套

/*  小端存储(低字节位——低地址位),  交叉存放  */
union Myunion
{
	int a;
	struct
	{
		char ch1;
		char ch2;
		char ch3;
		char ch4;
	};
};

// 16909320
// ‭0001,00000010,00000100,00001000‬
//   1        2       4        8


int main()
{
	Myunion u;
	int n =   16909320;
	u.a = n;
	printf("%d %d %d %d \n", u.ch1, u.ch2, u.ch3, u.ch4);
	// 8 4 2 1

	return 0;
}
嵌套 + 位域(位段)


union Myunion_bit
{
	int a;
	struct
	{
		unsigned char ch1 : 4;
		unsigned char ch2 : 4;
		unsigned char ch3 : 4;
		unsigned char ch4 : 4;
		unsigned char ch5 : 4;
		unsigned char ch6 : 4;
		unsigned char ch7 : 4;
		unsigned char ch8 : 4;
	};
};


// 16909320
// ‭0001, 0000 0010, 0000 0100, 0000 1000‬
//   1     0    2     0    4    0    8

int main()
{
	Myunion_bit u;
	int n = 16909320;
	u.a = n;
	printf("%d %d %d %d %d %d %d %d \n", u.ch1, u.ch2, u.ch3, u.ch4, u.ch5, u.ch6, u.ch7, u.ch8);
	// -8 0 4 0 2 0 1 0   当 ch 有符号
	//  8 0 4 0 2 0 1 0    当 ch 无符号
	return 0;
}

注:
在结构体中,如果类型为 char 类型。即有符号类型时,输出的u.ch1-8
分析:

  • 按照位域的特点,ch1应该分配了4 bit的二进制,1000
  • -8 的二进制是 1111 1000
  • 推测,在使用 u.ch1 时会将不完整的数据右移至完整。(右移符号位填充最高位数据)

检验代码:

	bitset<8>bit = u.ch1;
	cout << bit << endl; 	// 输出二进制
	bit = u.ch3;
	cout << bit << endl; 	// 输出二进制

输出结果:

11111000	// u.ch1 = -8
00000100	// u.ch3 = 4
嵌套 + 位域——关于内存对齐

在结构体划分位段时,会受到自身变量类型的影响。如果该类型剩余空间不足以继续分配位段,则会自动对齐至下一个内存单元中,进行分配。

错误代码:

union MyUnion
{
	unsigned short num;	// 16 位
	struct 
	{
		unsigned char al : 6;	// 低 6位
		unsigned char ah : 6;	// 中 6位
		unsigned char hh : 4;	// 高 6位
	};
};

int main()
{
	MyUnion un;
	un.num = 0x111;	// 0000 0001 0001 0001
	int n = un.hh;  //error: 使用了未初始化的局部变量“un”

	return 0;
}

在上述结构中,匿名struct内部使用了 char 类型的变量进行位段的划分,而 char 类型是以“一字节,八比特”进行内存对齐。因此我们在使用 struct 内第三个变量时产生错误。

过程分析:

  1. 我们期望的是,将 num 分为三部分存取到 al、ah、hh中。如下所示:
unsigned short num          =  0000 0001 0001 0001    

unsigned char al : 6; // 低 6位= 0000 0001 0001 0001
unsigned char ah : 6; // 中 6位= 0000 0001 0001 0001
unsigned char hh : 4; // 高 6位= 0000 0001 0001 0001

  1. 实际却是 ah 在划分位段时,由于 char类型 1字节内存对齐,在num的低字节中仅存 2 位比特位,不够 ah 的6位域,进而向后内存对齐使用 num 的高字节进行位段划分。所以 al 与 ah 对应获取的位段如下:

unsigned char al : 6; // 低 6位= 0000 0001 0001 0001
unsigned char ah : 6; // 中 6位= 0000 0001 0001 0001
因此, hh 就没有了可划分的位段。

解决方案:
unsigned char 类型换成 unsigned short ,使之在内存对齐时,使用2字节对齐。

union MyUnion
{
	unsigned short num;	// 16 位
	struct 
	{
		unsigned short al : 6;	// 低 6位
		unsigned short ah : 6;	// 中 6位
		unsigned short hh : 4;	// 高 6位
	};
};

此时 num、al、ah、hh 的值分别为:

un.num = 0x0111;	// 0000 0001 0001 0001

al = 0x0010 // 低 6位 0b00,01 0001
ah = 0x0004 // 中 6位 0b00,00 0100
hh = 0x0000 // 高 6位 0b00,00 0000


本质上,所有数据都通过二进制存储的内存或磁盘上,通过以上位域(位段)的学习,我们可以将char类型做到更小以便于达到一个比特,这样我们就可以直接从内存中提取到数据以二进制在内存中存储的最原始的状态。

因此,我们可以利用这一特点实现直接获取一个数据(这里主要指整数)的二进制表示:
数字转二进制(4种方法) | 位域(位段)应用 —— 从内存中提取数字的二进制

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫RT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值