打印

求助:在单片机对位域进行操作的疑问

[复制链接]
2440|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yuankunli|  楼主 | 2012-9-8 15:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位大神,在进行单片机编程中遇到个问题,一直没有弄明白。
例如:
typedef struct _ss_
{
unsigned char a: 4;
unsigned char b: 2;
}ss;
上面定义了两个位域变量,比如我想把ss.a这个位域变量赋值为二进制0110,这个应该如何写赋值语句呢?是ss.a=0110;吗?

相关帖子

沙发
yewuyi| | 2012-9-8 16:31 | 只看该作者
1、位变量赋值范围是0或者1,所以0110肯定就是你意象不到的错误了。
2、因为typedef,所以ss还只是一个类型,还不是变量,你可以用ss作为类型去定义一个变量,例如ss  kcnt;
则可以这样用kcnt.a=0;

使用特权

评论回复
板凳
yuankunli|  楼主 | 2012-9-8 17:20 | 只看该作者
2楼讲的很详细,使我受益匪浅。
那么我想赋值给kcnt.a,他在定义中为4位,那么赋值0110是不是直接用kcnt.a=0110吗?还是kcnt.a=6?
还是kcnt.a=0b0110?或者我看有些帖子上上是kcnt.a=(0xF1&0x60)>>4?特别是最后一种有时候赋值语句是不是可以达到最终将0110赋值给kcnt.a的目的?

使用特权

评论回复
地板
yewuyi| | 2012-9-8 17:48 | 只看该作者
Kcnt.a赋值只能是0或者1,如果赋值1,则意味Kcnt的第四位为1。
假如:Kcnt.a=0b0110;
则因为0b0110不为0,从位变量的角度看相当于真值1,在绝大多数编译器中,此时Kcnt.a的值为1.

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
yuankunli + 1
5
chenbb8| | 2012-9-9 08:48 | 只看该作者
位域可不可以赋值成0b0110,要看编译器支不支持了。
在AVRGCC中我记得是没有0b这种写法的,应该是C51的扩展语法吧
我表示位的时候喜欢这样搞:
#include<stdio.h>
#include<stdint.h>

#define BIT0 0x1/*使用宏定义来表示位 这样爽多了*/
#define BIT1 0x2
#define BIT2 0x4
#define BIT3 0x8
#define BIT4 0x10
#define BIT5 0x20
#define BIT6 0x40
#define BIT7 0x80

typedef struct _ss_
{
unsigned char a: 4;
unsigned char b: 2;
}ss;

main()
{
  ss Kcnt;
  Kcnt.a = BIT2 | BIT1;
  printf( "%d", Kcnt.a );
  system("pause");        //DEV-GCC的扩展的函数:等待任意按键
}

以上程序在DEV-C++中已经验证过,对Kcnt.a赋值BIT4以上的值的时候,会自动忽略超出定义位数以上的值。
对Kcnt.b赋值BIT0~7也不会溢出到Kcnt.a中。
个人对于位域有点理解不清的地方,是因为没有单片机中通过反汇编观察编译出来的代码,不清楚赋值的过程是怎么样的(位与或还是位移?),到底使用位域会不会损失性能?并且位域在移植到不同的单片机(大小端、8/32位)的时候可能出现问题,因此我尽量不用位域

kcnt.a=(0xF1&0x60)>>4,由于(0xF1&0x60)>>4是常量运算,因此编译器会优化掉,所以结果和直接赋值0X6是一样的。不清楚为什么要写的那么复杂。

使用特权

评论回复
评分
参与人数 2威望 +2 收起 理由
lovegan + 1 赞一个!
yuankunli + 1
6
原野之狼| | 2012-9-9 23:45 | 只看该作者
叶工对位域的理解存在错误,4表示占4位,而不是第4位,所以并不是0或1两种取值。
对位域变量赋值时直接使用=就行,举例:
var.a = 1;  // OK
var.a = 0;  // OK
var.a = 10; // OK
var.a = 15; // OK
var.a = 16; // OK 但是此时超范围被截断,实际上var.a = 0,编译器会warning
var.a = 100; // OK 但是此时超范围被截断,实际上var.a = 4,编译器会warning

对var.b的操作同上,不需要进行移位操作。
var.b = 0; // OK
var.b = 1; // OK
var.b = 5; // OK 但是此时超范围被截断,实际上var.b= 1,编译器会warning

至于赋值时右值采用十进制、十六进制还是二进制都无所谓。

使用特权

评论回复
7
yewuyi| | 2012-9-10 09:03 | 只看该作者
叶工对位域的理解存在错误,4表示占4位,而不是第4位,所以并不是0或1两种取值。
对位域变量赋值时直接使用=就行,举例:
var.a = 1;  // OK
var.a = 0;  // OK
var.a = 10; // OK
var.a = 15; // OK
var.a = 16; // ...
原野之狼 发表于 2012-9-9 23:45


'叶工对位域的理解存在错误,4表示占4位,而不是第4位,所以并不是0或1两种取值。
'


重新看了一下,确实我理解混了,误导了LZ,实在抱歉。

使用特权

评论回复
8
ayb_ice| | 2012-9-11 11:23 | 只看该作者
4位的位域可取会聚取值0~15的

使用特权

评论回复
9
渤海三叠浪| | 2012-9-11 12:27 | 只看该作者
什么叫做位域

所谓位域  就是不需要了解的意思。
就是说楼主没必要知道。你想连叶公都搞错你 楼主你能每次都弄对么?

使用特权

评论回复
10
xsjkiver| | 2012-9-11 13:06 | 只看该作者
个人意见:就现在的硬件配置而言,我想根本没必要使用位域吧

使用特权

评论回复
11
ronic| | 2012-9-13 13:53 | 只看该作者
位域还是有它方便的地方。跟硬件配置无关。
10# xsjkiver

使用特权

评论回复
12
diweo| | 2012-9-13 18:00 | 只看该作者
有问题是正常的,但是这个问题一直弄不明白就有点不应该了。
LZ你自己都有好几种猜想,为什么不写到代码里呢?程序调试运行一下不就知道了吗?

使用特权

评论回复
13
joyme| | 2012-9-13 18:16 | 只看该作者
位域的方便之处在于同时操作多个位语句最简单
不用位域,同时操作几位,最简单的办法是先将这些位清0,再或上要设置的值
用位域可以直接将设置的值赋给相应的位域

使用特权

评论回复
14
dqyubsh| | 2012-9-13 20:07 | 只看该作者
位域还有一个好处是在不同硬件间移植,比如,C51移植到AVR平台。

没觉得和union有太大差别。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

29

帖子

1

粉丝