bit feild and CPU endian 位域和大小端

先看一个示例:
// C code: bit fields & CPU endian
#include <stdio.h>

struct bit_field{
    unsigned short bit4:4;
    unsigned short bit3:3;
    unsigned short bit2:2;
    unsigned short bit7:7;
};

int main()
{
    struct bit_field bit;

    bit.bit4=10;
    bit.bit3=5;
    bit.bit2=1;
    bit.bit7=8;

    printf("%x\r\n", *(unsigned short *)&bit);
    return 0;
}
在big-endian机器上的结果是aa88
1010,101,01,0001000 (10 5 1 8)
1010,1010,1000,1000 ( A  A 8 8)

在small-endian机器上的结果是10da
0001000,01,101,1010 (8 1 5 10)
0001,0000,1101,1010 (1 0 D  A )

位域操作在不同系统中有两处是不同的
1 编译器编译结果是不同的
        因为CPU对于存储器不能进行位操作,每次读写的最小单位是字节,所以每次位域赋值操作编译器都要将位域的值转换为一个或多个字节长度的数值,将这个数值与存储器中原有的值进行或操作;配置了不同CPU类型的编译器对于相同的位域转换成的数值是不一样的,对于配置CPU类型为MPC8260的,gcc编译器它将结构中先声明的位域做为该位域所属结构元素的高位,后声明的位域做为结构元素的低位,而VC编译器正相反,它将先声明的位域做为结构元素的低位,后声明的位域做为结构元素的高位,为了便于理解可以认为编译器先将结构元素中的各个位域组成一个数值,这个数值的字长等于结构元素的字长,然后通过寄存器将该数值写入存储器中,配置CPU类型为MPC8260的gcc编译器将先声明的位域做为数值高位,而VC编译器将后声明的位域做为高位。因此对于struct bit_field这个结构元素,gcc编译器认为它的值是0xaa88,而VC编译器认为它的值是0x10da。

2 CPU将寄存器的值写入存储器时字节排序是不同的
       因为MCP8260是big-endian模式,运行VC的PC机CPU是Intel系列的采用little-endian模式,所以MPC8260将寄存器内容写入存储器时,将高位字节0xaa写入低地址,将低位字节0x88写入高地址。Intel的CPU正相反,它将高位字节0x10写入高地址,将低位字节0xda写入低地址。位域赋值语句要经过编译过程和执行过程才会转换成存储器中的数值,位域转换到数值的过程发生在编译阶段,将转换后的数值通过寄存器写入存储器之间的操作发生在代码的执行阶段,前者因为编译器不同位域转换成的值也不同,后者因为CPU类型不同而存在着little-endian和big-endian的差异

总结:
       在存储顺序问题上,位域操作有其独特之处,它的存储顺序是CPU和编译器双重作用的结果,CPU决定字节的存储顺序,编译器决定位域的存储顺序。

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编就啥都明白了。(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)

link for bit feild basic:

    http://blog.sina.com.cn/s/blog_3d8529400100istl.html

    http://msdn.microsoft.com/zh-cn/library/yszfawxh.aspx

Here are two usefull code for getting CPU endian type and code for declarator in bit field definition.

//C code: get CPU big endian or small endian
#include <stdio.h>

union TEST{
	unsigned char aa[4];
	unsigned int  bb;
};

int main()
{
	union TEST test;

	test.aa[0] = 0x01;
	test.aa[1] = 0x02;
	test.aa[2] = 0x03;
	test.aa[3] = 0x04;

	if (test.bb == 0x01020304)
		printf("it's big endiam!\r\n");
	else if (test.bb == 0x04030201)
		printf("it's small endiam!\r\n");
	else
		printf("unknow endiam system! 0x1234 VS 0x%x\r\n", test.bb);

	return 0;
}
// C code: sizeof bit operation 
#include <stdio.h>

struct TEST1{
	unsigned short bit4:4;
	unsigned short bit3:3;
	unsigned short bit2:2;
	unsigned short bit7:7;
};
struct TEST2{
	unsigned short bit4:4;
	unsigned short bit3:3;
	unsigned short bit2:2;
	unsigned short bit7:7;
	double bb;
};
struct TEST3{
	unsigned int bit4:4;
	unsigned int bit3:3;
	unsigned int bit2:2;
	unsigned int bit7:7;
};
struct TEST4{
	unsigned int bit4:4;
	unsigned int bit3:3;
	unsigned int bit2:2;
	unsigned int bit7:7;
	double bb;
};

int main()
{
	printf("%d, %d; %d, %d; %d\r\n", sizeof(TEST1), sizeof(TEST2),
                                   sizeof(TEST3), sizeof(TEST4), sizeof(double));
	return 0;
}

result: 2, 16; 4, 16; 8


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值