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

普通嵌套

/*  小端存储(低字节位——低地址位),  交叉存放  */
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

你可能感兴趣的:(日常心得)