您当前的位置:首页 > 计算机 > 编程开发 > C语言

C语言中的位屏蔽(bit masking)是怎么回事

时间:12-30来源:作者:点击数:

位屏蔽的含义是从包含多个位集的一个或一组字节中选出指定的一(些)位。为了检查一个字节中的某些位,可以让这个字节和屏蔽字(bit mask)进行按位与操作(C的按位与运算符为&)——屏蔽字中与要检查的位对应的位全部为1,而其余的位(被屏蔽的位)全部为0。例如,为了检查变量flags的最低位,你可以让flags和最低位的屏蔽字进行按位与操作:
    flags&1;

为了置位所需的位,可以让数据和屏蔽字进行按位或操作(C的按位或运算符为|)。例如,你可以这样置位flags的最低位:
    flags = flags | 1;

或者这样:
    flags |= 1;

为了清除所需的位,可以让数据和对屏蔽字按位取反所得的值进行按位与操作。例如,你可以这样清除flags的最低位:
    flags = flags& ~1;

或者这样:
    flags&=~1 ;

有时,用宏来处理标志会更方便,例10.2中的程序就是通过一些宏简化了位操作。

例10.2 能使标志处理更方便的宏

/* Bit Masking * /
/* Bit masking can be used to switch a character between lowercase and uppercase */
#define BIT_POS(N)            ( 1U «(N) )
#define SET_FLAG(N,F)         ( (N) |  = (F) )
#define CLR_FLAG(N,F)         ( (N) &= -  (F) )
#define TST_FLAGCN,F)         ( (N) & (F)  )
#define BIT_RANGE(N,M)         ( BIT_POS((M) + 1- (N))-1<<(N))
#define BIT_SHIFTL(B,N)        ( (unsigned)(B)«(N) )
#define BIT_SHIFTR(B,N)        ( (unsigned)(B)»(N) )
#define SET_MFLAG(N,F,V)       ( CLR_FLAG(N,F), SET_FLAG(N,V) )
#define CLR_MFLAG(N,F)         ( (N) &= ~(F) )
#define GET_MFLAG(N,F)         ( (N) & (F) )

# include <stdio. h>
void main()
{
  unsigned char ascii_char = 'A';    /* char  = 8 bits only */
  int test_nbr = 10;
  printf("Starting character =  %c\n" , ascii_char);
  /*   The 5th bit position determines if the character is
       uppercase or lowercase.
       5th bit =  0 - Uppercase
       5th bit =  1- Lowercase    */
  printf ("\nTurn 5th bit on = %c\n" , SET_FLAG(ascii_char, BIT_POS(5)));
  printf ("Turn 5th bit  off = %c\n\n",CLR_FLAG(ascii_char, BIT_POS(5)));
  printf ("Look at shifting bits\n");
  printf (" = = = = = = = = = = = = = = = =\n" );
  printf ("Current value = %d\n" , test_nbr)i
  printf ("Shifting one position left = %d\n" ,test_nbr = BIT_SHIFTL(test_nbr, 1) );
  printf ("Shifting two positions right =  %d\n" ,BIT_SHIFTR(test_nbr,  2) );
}

宏BIT_POS(N)能返回一个和N指定的位对应的屏蔽字(例如BIT_POS(O)和BIT_POS(1)分别返回最低位和倒数第二位的屏蔽字),因此你可以用
    #define A_FLAG BIT_POS(12)
    #define A_FLAG BIT_P0S(13)

代替
    #define A_FLAG 4096
    #define A_FLAG 8192

这样可以降低出错的可能性。

宏SET_FLAG(N,F)能置位变量N中由值F指定的位,而宏CLR_FLAG(N,F)则刚好相反,它能清除变量N中由值F指定的位。宏TST_FLAG(N,F)可用来测试变量N中由值F指定的位,例如:
    if (TST_FLAG (flags, A_FLAG))
          /* do something */;

宏BIT_RANGE(N,M)能产生一个与由N和M指定的位之间的位对应的屏蔽字,因此,你可以用
    # define FIRST_OCTAL_DIGIT     BIT_RANGE (0,2)   /*111"/
    # define SECOND-OCTAL-DIGIT    BIT-RANGE(3,5)    /* 111000*/

代替
    #define FIRST_OCTAL_DIGIT 7      /*111*/
    #define SECOND_OCTAL_DIGIT 56    /* 111000 */

这样可以更清楚地表示所需的位。

宏BIT_SHIFT(B,N)能将值B移位到适当的区域(从由N指定的位开始)。例如,如果你用标志C表示5种可能的颜色,你可以这样来定义这些颜色:

    #define C_FLAG        BIT-RANGE(8,10)     /* 11100000000 */
   /* here are all the values the C flag can take on */  
   # define C_BLACK   BIT-SHIFTL(0,8)   /* ooooooooooo */
   # define C-RED     BIT_SHIFTL(1,8)   /* 00100000000 */
   # define C-GREEN   BIT_SHIFTL(2,8)   /* 01000000000 */
   # define C-BLUE    BIT-SHIFTL(3,8)   /* 01100000000 */
   # define C_WHITE   BIT-SHIFTL(4,8)   /* 10000000000 */
   # defineC-ZERO C-BLACK  
   # defineC-LARGEST C-WHITE  
   /* A truly paranoid programmer might do this */
   #if C_LARGEST > C_FLAG
          Cause an error message. The flag C_FLAG is not
          big enough to hold all its possible values.
   #endif /* C_LARGEST > C_FLAG */

宏SET_MFLAG(N,F,V)先清除变量N中由值F指定的位,然后置位变量N中由值V指定的位。宏CLR_MFLAG(N,F)的作用和CLR_FLAG(N,F)是相同的,只不过换了名称,从而使处理多位标志的宏名字风格保持一致。宏GET_MFLAG(N,F)能提取变量N中标志F的值,因此可用来测试该值,例如:
    if (GET_MFLAG(flags, C_FLAG) == C_BLUE)
         /*do something */;

注意:宏BIT_RANGE()和SET_MFLAG()对参数N都引用了两次,因此语句
    SET_MFLAG(*x++,C_FLAG,C_RED);

的行为是没有定义的,并且很可能会导致灾难性的后果。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门