1 联合体
(1)联合体机制
联合体的所有成员引用的是内存中的相同地址。访问联合的不同成员时,会根据此成员的类型去访问对应的字节,并根据此成员的类型去解释这些字节对应位的含义(表示int还是float)。
联合体初始化时,初始化的是联合的第一个成员(所以类型应该与联合的第一个成员相同,否则会发生类型转换),而且初始值必须位于一对大括号内。
(2)用联合体测平台数据存储是大端还是小端
要想知道平台采用的大端还是小端的方式存储数据,可以看.c文件对应的目标文件或者可执行文件。在知道系统采用的存储方式后,可以反推内存地址采用的高地址还是低地址来表示。
联合体my_test中的i和ch的内存地址相同。不同的是,访问my_test.i时会读sizeof(unsigned int)字节内容并按照int类型解释这些位;访问my_test.ch时会读一个字节内容并按照char类型(实质是int)解释这些位。
my_test经初始化后,my_test.ch与my_test.i的第一个字节(表示整个变量的地址)内容相同。如果系统采用低地址来作为一个类型的地址(int占4个字节,用4个字节中的最低地址表示int变量的地址),那么以上程序就能够测试出系统采用的大端还是小端方式存储数据。如果my_test.ch值为1则表示系统采用小端方式存储数据,否则为大端方式。如果系统采用高地址来作为一个类型的地址,那么my_test.ch值为1则表示系统采用大端方式存储数据,否则为小端方式。
将这段代码放在main函数中,某次运行的结果如下:
--------------test_endian function------------------
address of i = 0xbff03cdc
address of ch = 0xbff03cdc
ch = 1
hex dump of ch = 0x1
This platom uses litte endian
已经在某.c文件的目标文件中得知/x86/Debian GNU/Linux平台采用的小端方式存储数据,故而得它用的低地址表示内存段地址。
2 位段
(1)结构体成员的存储地址
数组元素的地址按照下标连续递增。结构体内的成员的地址虽不连续,但会按照成员的定义顺序各成员的地址会由低到高。
(2)位段的存储
将这个函数放在main函数中,某次运行得到的结果如下:
--------------test_bit_field_layout---------------
value of byte:
byte[0] = 2 byte[1] = 9 byte[2] = 33 byte[3] = 0
hex dump of byte:
byte[0] = 0x2 byte[1] = 0x9 byte[2] = 0x21 byte[3] = 0x0
分析各位段存储的数据(以小端的方式存储):
如果将未命名的字段unsignedint :4;屏蔽,则程序运行如下:
--------------test_bit_field_layout---------------
value of byte:
byte[0] = 2 byte[1] = 25 byte[2] = 2 byte[3] = 0
hex dump of byte:
byte[0] = 0x2 byte[1] = 0x19 byte[2] = 0x2 byte[3] = 0x0
则各位段存储的数据(以小端的方式存储):
与一般结构体一样,为了访问的效率,编译器可能会在两个位段间及结构体末尾加入填充位。
关于如何排列Bit-field在C标准中没有详细的规定,这跟Byte Order、Bit Order、对齐等问题都有关,不同的平台和编译器可能会排列得很不一样,要编写可移植的代码就不能假定Bit-field是按某一种固定方式排列的。同时Bit-field在驱动程序中是很有用的,因为经常需要单独操作设备寄存器中的一个或几个bit,但一定要小心使用,首先弄清楚每个Bit-field和实际bit的对应关系。