C语言中位域的详解

C 语言中位域的详解在对STM8L 进行引脚的位控制时,看到了很多类似下面的定义:typedefstruct{unsigned char PORF : 1;unsigned char I

C 语言中位域的详解

在对STM8L 进行引脚的位控制时,看到了很多类似下面的定义:

typedefstruct

{

unsigned char PORF : 1;

unsigned char IWDGF : 1;

unsigned char ILLOPF : 1;

unsigned char SWIMF : 1;

} __BITS_RST_SR;

从而引发了对C 语言中位域的探索,至今至少弄明白了一些,记下来。 首先引用百度文库中关于位域的探讨:

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为: struct 位域结构名

{ 位域列表 };

其中位域列表的形式为:类型说明符位域名:位域长度

经过上面位域的解释,基本上对其中所占1位的位域操作有所了解,例如: Struct x

{

Unsigned char a :1;

}

x.a=1;或者x.a=0;

这样便可以将单位赋值成0或者1。

那么这样我们便产生一个疑问,若是定义的位域不是1位而是多位呢?例如 Struct x

{

Unsigned char a:4;

}

x.a=0110;可以这样赋值吗?

经过一番不严谨的查询和编程验证,在VS2010软件条件下,编写一个C 语言输出小程序,如下(主要写关键代码)例一:

Struct x

{

Unsigned char a:4;

}

x.a=0xF;

,

printf("x",x.a);

这样输出为F 。之所以这样写程序,由于x.a 定义为只有4位的变量,赋值时用十六进制来表示所要的数值,若想赋值一个二进制,在这样的软件条件下也可以这样赋值:x.a=1111;那么输出x.a 变量时结果也是F 。为什么会这样?

我认为无论在程序语句中我们怎么给一个变量赋值,其实在物理存储时都是以二进制保存的,所以只要在编译器允许的条件下上述两种赋值都是可以。下面将下单片机的软件环境可以在赋值上有些限定,例如有的赋值二进制需要:x.a=0b1111;

还有看见有些百度知道或者论坛帖子上有人出现过输出结果并不是他想要的,例如:例二

赋值结果让人想不通:

typedefstruct _ss_

{

int a:2;

int b:2;

int c:2;

int d:1;

}ss;

ssff;

intuu

ff.a=1;

ff.b=2;

ff.c=3;

ff.d=4;

uu = ff.a; //uu结果为1,没疑问

uu = ff.b; //uu结果为0xfffffffe ,为什么?不是应该是2吗? uu = ff.c; //uu结果为0xffffffff, 为什么?我觉得应该是3啊

uu = ff.d; //uu结果为0,正确

这里面存在很多问题,先说下uu 结果为0xfffffffe ,为什么?不是应该是2吗?

首先这位童鞋使用的是32位系统的电脑,所以输出0xfffffffe ,共32位,因为在位域定义时,int 在32位系统中是占32位存储的,所以将定义中int 改为unsigned char;其次,在d 赋值时会出现溢出的情况;最后,有些童鞋在输出时printf 中使用十进制输出,在遇到例一中若将x.a=1111;那么电脑输出结果为7,出现了偏差,这样是不行的,若想输出十进制,那么写个小函数进行下十六进制转化为十进制,才可以。若是在单片机C 语言编程中,对寄存器进行位操作中,则无需输出,也无需转化了。

这里只是讨论了位域的一些赋值的小讨论,这里我胡乱说了半天,也不知道对不?若有错误,还请指正。关于位域在物理的存储方式很多资料都讨论过了,这里就不展开讨论。

标签: