C语言中的段位操作

1.位段结构中位段的定义格式为: 
unsigned <成员名>:<二进制位数> 
例如: 
struct bytedata 
{unsigned a:2; /*位段a,占2位*/ 
unsigned:6; /*无名位段,占6位,但不能访问*/ 
unsigned:0; /*无名位段,占0位,表下一位段从下一字边界开始*/ 
unsigned b:10; /*位段b,占10位*/ 
int i; /*成员i,从下一字边界开始*/ 
}data; 
2.
(1)一个位段必须存储在同一存储单元(即字)之中,不能跨两个单元。如果其单元空间不够,则剩余空间不用,从下一个单元起存放该位段。 
(2)可以通过定义长度为0的位段的方式使下一位段从下一存储单元开始。
(3)可以定义无名位段。 
(4)位段的长度不能大于存储单元的长度。 
(5)位段无地址,不能对位段进行取地址运算。
(6)位段可以以%d,%o,%x格式输出。 
(7)位段若出现在表达式中,将被系统自动转换成整数。 

拷贝2:

C语言中的结构是有实现位段的能力的,噢!你问它到底是什么形式是吧?这个问题呆会给你答案。让我们先看看位段的作用:位段是在字段的声明后面加一个冒号以及一个表示字段位长的整数来实现的。这种用法又被就叫作“深入逻辑元件的编程”,如果你对系统编程感兴趣,那么这篇文章你就不应该错过!
我把使用位段的几个理由告诉大家:

1、它能把长度为奇数的数据包装在一起,从而节省存储的空间;

2、它可以很方便地访问一个整型值的部分内容。

首先我要提醒大家注意几点:

1、位段成员只有三种类型:

int ,unsigned int 和signed int这三种(当然了,int型位段是不是可以取负数不是我说了算的,因为这是和你的编译器来决定的。位段,位段,它是用来表示字段位长(bit)的,它只有整型值,不会有7.2这种float类型的,如果你说有,那你就等于承认了有7.2个人这个概念,当然也没有char这个类型的);

2、成员名后面的一个冒号和一个整数,这个整数指定该位段的位长(bit);

3、许多编译器把位段成员的字长限制在一个int的长度范围之内;

4、位段成员在内存的实现是从左到右还是从右到左是由编译器来决定的,但二者皆对。

下面我们就来看看,它到底是什么东西(我先假定大家的机器字长为32位):
  Struct WORD
  {
unsigned int chara: 6:
unsigned int font : 7;
unsigned int maxsize : 19;
  };
  Struct WORD chone;
  这一段是从我编写的一个文字格式化软件摘下来的,它最多可以容纳64(既我说的unsigned int chara :6; 它总共是6位)个不同的字符值,可以处理128(既unsigned int font : 7 ;既2的7次方)种不同的字体,和2的19次方的单位长度的字。大家都可以看到maxsize是19位,它是无法被一个short int 类型的值所容纳的,我们又可以看到其余的成员的长度比char还小,这就让我们想起让他们共享32位机器字长,这就避免用一个32位的整数来表示maxsize的位段。怎么样?还要注意的是刚才的那一段代码在16位字长的机器上是无法实现的,为什么?提醒你一下,看看上面提醒的第3点,你会明白的!
你是不是发现这个东西没有用啊?如果你点头了,那你就错了!这么伟大的创造怎么会没有用呢(你对系统编程不感兴趣,相信你会改变这么一个观点的)?磁盘控制器大家应该知道吧?软驱与它的通信我们来看看是怎么实现的下面是一个磁盘控制器的寄存器:
│←5→│←5→│←9→│←8→│←1→│←1→∣←1→∣←1→∣←1→∣
  上面位段从左到右依次代表的含义为:5位的命令,5位的扇区,9位的磁道,8位的错误代码,1位的HEAD LOADED,1位的写保护,1位的DISK SPINNING,1位的错误判断符,还有1位的READY位。它要怎么来实现呢?你先自己写写看:
  struct DISK_FORMAT
  {
   unsigned int command : 5;
     unsigned sector : 5;
   unsigned track : 9 ;
   unsigned err_code : 8;
   unsigned ishead_loaded : 1;
   unsigned iswrit_protect : 1;
   unsigned isdisk_spinning : 1;
   unsigned iserr_ocur : 1;
   undigned isready :1 ;
  }; 
  注:代码中除了第一行使用了unsigned int 来声明位段后就省去了int ,这是可行的,详见ANCI C标准。
  如果我们要对044c18bfH的地址进行访问的话,那就这样:
  #define DISK ((struct DISK_FORMAT *)0x044c18bf)
  DISK->sector=fst_sector;
  DISK->track=fst_track;
  DISK->command=WRITE;
  当然那些都是要宏定义的哦!
  我们用位段来实现这一目的是很方便的,其实这也可以用移位或屏蔽来实现,你尝试过就知道哪个更方便了!

 

测试代码:

#i nclude <stdio.h>

int main()
{
    struct
    {
        unsigned short s1 : 4;
        unsigned short s2 : 3;
        unsigned short s3 : 2;
    }x;
    
    char c= 0x7A; // 0111 1010 b
    x.s1 = c;
printf( "%x/n", x.s1 );
return 0;
}

根据编译器的不同,可能出现大端和小端的问题,小端就是从低位开始取值,大端就是从高位取值。

常见为小端模式。

永不止步步 发表于10-17 11:04 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67417个|学分:363741个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号