C/C++位操作简介

之前一直对C/C++里面的位操作不是太理解,遇到可能要用的地方也想尽办法用其他方式来解决,算是有点讳疾忌医吧。但是,今天在刷LeetCode时候才发现,在一些有特定要求的特定问题下(比如对时间复杂度和内存的要求),位操作反而会起到迅速解决问题的作用,因此特地将一篇关于C/C++位操作的学习文章转载下来。下面的内容是转载自http://blog.163.com/wwxwb_913/blog/static/976853620106682126626/,(虽然不知道这个链接是否是原创)


C++位操作介绍

C++位操作包括两种:传统的C语言方式的位操作和C++中利用bitset容器的位操作 
一、传统的C方式位操作:
1.基本操作:
   使用一个unsigned int变量来作为位容器。
2.操作符: " ~- i  [' f3 k4 i9 I
|   按位或操作符:result=exp1|exp2;当exp1和exp2中对应位中至少有一个为1时,result中对应位为1,否则为0。 3 W4 A6 K, o0 s0 j
&  按位与操作符::result=exp1&exp2;当exp1和exp2中对应位全为1时,result中对应位为1,否则为0。
^  按位异或或操作符:result=exp1^exp2;当exp1和exp2中对应位不相同时,result中对应位为1,否则为0。
~  反转操作符:将位容器中的所有位都反转,1变为0,0变为1。 7 t7 k* A" t  M9 r6 ]( F0 {6 P
<< 按位左移操作符:exp<<n,将容器中所有的位向左移n位,空出的位用0填充。
>> 按位右移操作符:exp>>n,将容器中所有的位向右移n位,空出的位用0填充。 + s* j# ^+ n: Q6 L: `2 n
|=,&=,^= 分别对应|&^三种操作符的复合操作符。
3.常用操作
这里我们假设有一个result的unsigned int变量用来储存32个学生的成绩(通过和不通过分别用0和1),这样result就有33位(result从右至左,从0开始计算位数,在这个例子中0位被浪费)。
(a) 将第27位设置为及格(设作1)其他位不变:
   result|=(1<<27) //任意的位值与1作按位或操作其值为1,而与0作按位与操作其值不变   J% b  \- c8 v" K
(b) 将第27位设置成不及格(设为0)。
   result&=~(1<<27) //任意的位值与0作按位与操作其值为0,而与1作按位与操作其值不变
(c) 反转第27位的值。
   result^=(1<<27) //任意的位值与1作按位异或操作其值为1,而与0作按位异与操作其值不变 0 |$ s( ]* G- x2 `5 b7 q. Y0 Y* Y
* G. R$ a6 m+ Q
二、C++中的bitset容器3 A$ w% O9 y* H. d
1.头文件:

  #include <bitset> + ~* A' z" i8 \4 b6 @" X8 R
2.声明一个容器: * ]6 S# p- Q7 \
(a)声明一个指定位数的空容器(所有位设为0): bitset<int> bits; 8 O7 A& b  w' Y8 r. W+ I& T' {: E
(b)声明一个指定位数并将指定的几个位初始化为相应值的容器: bitset<n> bits(int); ; e- S+ V1 l* g( x  `& [
     bitdet<int> bits(string&) # Z! X( ]8 o& O7 w3 r) l$ |
总结:bitset模板类中类型参数传递容器的位数,而构造函数参数通过一个int或一个string&值来从右至左初始化容器中的相应值。
3.bitset的基本用法: % I" V3 W+ P5 A& h0 v$ W- F
操作                            功能                                   用法 : L( G2 H; z8 X% G/ ^1 d* J
test(pos)                       pos位是否为1                    a.test(4) . s$ Q) V' p0 L* i/ i
any()                            任意位是否为1                   a.any()
none()                          是否没有位为1                   a.none() ) o6 R0 }7 a! O' E- m& s
count()                         值是1的位的小数              a.count()
size()                           位元素的个数                     a.size() $ v7 l% J% P9 |5 y0 P1 x) \
[pos]                            访问pos位                         a[4] 6 {& Q1 |+ x: q! a' F  [+ t
flip()                            翻转所有位                         a.flip()
flip(pos)                       翻转pos位                         a.flip(4) : g+ ~0 {0 u# v2 J* l) B4 {. i, ]
set()                             将所有位置1                      a.set()
set(pos)                        将pos位置1                       a.set(4)   x' u4 f& P! e9 t5 B: }- L/ g5 R
reset()                          将所有位置0                      a.reset() 3 T# |; |  ]5 G- G2 n
reset(pos)                            将pos位置0                       a.reset(4) 0 p( L4 j" T7 V$ m
4.bitset与传统C位操作及字符串的转换
   可以通过to_string()成员将容器转输出为一个string字符串,另外还可以用to_long()成员将容器输出到传统的用于C风格的位容器中。如: : h& q  Q- v1 q* X# R1 a' _
  unsigned long bits = bits.to_long();
  sting str(bits.to_string());

C语言中常见的置位操作 如何对某一位置0或者置1?
方法一: % l- U6 {* a5 B6 ?* C: R
写成宏,方便移植 ! U0 O2 \( ~* n' V
#define setbit(x,y) x|=(1<<y) //将X的第Y位置1
#define clrbit(x,y) x&=!(1<<y) //将X的第Y位清0


方法二:
C语言位运算除了可以提高运算效率外,在嵌入式系统的编程中,它的另一个最典型的应用,而且十分广泛地正在被使用着的是位间的与(&)、或(|)、非(~)操作,这跟嵌入式系统的编程特点有很大关系。我们通常要对硬件寄存器进行位设置
+ ~  a* u# f/ u' }6 e2 r
譬如,我们通过将AM186ER型80186处理器的中断屏蔽控制寄存器的 ) G; V! j: l: _" F
第低6位设置为0(开中断2),最通用的做法是: & p9 c3 v" f( r+ p
#define INT_I2_MASK 0x0040 
wTemp = inword(INT_MASK);
outword(INT_MASK, wTemp &~INT_I2_MASK); 
* @$ J6 {' D" e0 T" f
而将该位设置为1的做法是:
#define INT_I2_MASK 0x0040 
wTemp = inword(INT_MASK);: F# K9 X" n* v: ~: I, ~& [
outword(INT_MASK, wTemp | INT_I2_MASK); 

判断该位是否为1的做法是:
#define INT_I2_MASK 0x0040 . F+ J6 q: e4 U
wTemp = inword(INT_MASK);
if(wTemp & INT_I2_MASK)
{7 @6 G$ o" u7 C
… /* 该位为1 */

方法三: 6 x) `# f4 i1 ^* B! t  q
int a|=(1<<x) //X就是某位需要置1的数字,如第四位置1为: a|=(1<<4)
int b&=~(1<<x) //把某位置0 : ?* y; e$ z6 R& r, ^9 o! d* V
x=x|0x0100    //把第三位置1
x=x&0x1011    //把第三位置0
#define BitGet(Number,pos) ((Number) >> (pos)&1)) //用宏得到某数的某位
#define BitGet(Number,pos) ((Number) |= 1<<(pos)) //把某位置1 7 @( |& u2 e* i% X7 @
#define BitGet(Number,pos) ((Number) &= ~(1<<(pos)) //把某位置0   ?* ^3 c2 q# L3 r
#define BitGet(Number,pos) ((Number) ^= 1<<(pos)) //把Number的POS位取反
典型操作有:
WTCON |=  (1 << 5) //WTCON的第五位清1  6 m: J, ]' h! q/ l
WTCON &= ~(1 << 5) //WTCON的第五位清0   / R6 o6 n" {( {- r7 p

上述方法在嵌入式系统的编程中是非常常见的,我们需要牢固掌握

C/C++位操作技巧  检测一个无符号数是不为2^n-1(^为幂):   x&(x+1)   
     / f; Z7 o' L3 s& G+ a
  将最右侧0位改为1位:   x   |   (x+1)    4 [4 T. ^1 M1 t- T" c/ w
     # M+ k; i( [9 F$ h" S- j/ a
  二进制补码运算公式:   
  -x   =   ~x   +   1   =   ~(x-1)    ; I( R( }# }& V. y2 y* u0 H5 @/ S8 D3 C
  ~x   =   -x-1     
  -(~x)   =   x+1   
  ~(-x)   =   x-1    + ?; M2 @# _6 x3 b3 a
  x+y   =   x   -   ~y   -   1   =   (x|y)+(x&y)      ) S+ i# \. ^$ x; S
  x-y   =   x   +   ~y   +   1   =   (x|~y)-(~x&y)     
  x^y   =   (x|y)-(x&y)   
  x|y   =   (x&~y)+y   
  x&y   =   (~x|y)-~x   
    
  x==y:         ~(x-y|y-x)   
  x!=y:         x-y|y-x    5 R0 h0 c( a1 x0 }
  x<   y:         (x-y)^((x^y)&((x-y)^x))   
  x<=y:         (x|~y)&((x^y)|~(y-x))   
  x<   y:         (~x&y)|((~x|y)&(x-y))//无符号x,y比较   
  x<=y:         (~x|y)&((x^y)|~(y-x))//无符号x,y比较   
     / J$ s4 |3 t; s$ W# l3 d% R2 F
     * M+ p( ?) V. {: k
  使用位运算的无分支代码:    2 D+ g. V2 |5 Q) v8 V/ f9 b
    
  计算绝对值    . U( z* |! L! D, P9 Z
  int   abs(   int   x   )     
  {    , \' e8 l2 M8 v8 Q9 O. s
  int   y   ;   
  y   =   x   >>   31   ;    4 `% p/ |  s2 w+ b6 X
  return   (x^y)-y   ;//or:   (x+y)^y    ) |* ^+ |+ w. ~0 e& u
  }    3 Y9 E. b* o& B
     ' _3 p! m: N1 ~( P) d: V
  符号函数:sign(x)   =   -1,   x<0;   0,   x   ==   0   ;   1,   x   >   0   
  int   sign(int   x)    $ ?4 @! _! M" J& M
  {   
  return   (x>>31)   |   (unsigned(-x))>>31   ;//x=-2^31时失败(^为幂)    8 I- e8 {3 z& x2 v7 `. I
  }   
    
  三值比较:cmp(x,y)   =   -1,   x<y;   0,   x==y;   1,   x   >   y   
  int   cmp(   int   x,   int   y   )   
  {    6 I8 m9 p2 {6 @  V7 b
  return   (x>y)-(x-y)   ;   
  }   
     : p; f+ n" w. G4 E; p
  doz=x-y,   x>=y;   0,   x<y   
  int   doz(int   x,   int   y   )   
  {   
  int   d   ;    2 F* c+ X% E- `! _0 _" p+ ~
  d   =   x-y   ;    - v  c- `# D2 Q- r; l3 k
  return   d   &   ((~(d^((x^y)&(d^x))))>>31)   ;    8 }+ v; {$ `- O' G! e7 X
  }    * D4 G! n+ M% X! l: n
    
  int   max(int   x,   int   y   )     
  {   
  int   m   ;    0 P0 {% A2 R' a+ G& s- ]
  m   =   (x-y)>>31   ;      $ g& X+ f, A- }
  return   y   &   m   |   x   &   ~m   ;    6 H$ ~8 r0 t& ~. f
  }    # H! F4 t8 C9 z/ o1 x
    
  不使用第三方交换x,y:   
  1.x   ^=   y   ;   y   ^=   x   ;   x   ^=   y   ;    8 b+ t, a- x# ~/ u4 _, J/ Y
  2.x   =   x+y   ;   y   =   x-y   ;   x   =   x-y   ;   
  3.x   =   x-y   ;   y   =   y+x   ;   x   =   y-x   ;    0 u4 V" ~3 _+ v6 S# v% B8 P" g6 k. I
  4.x   =   y-x   ;   x   =   y-x   ;   x   =   x+y   ;     
    
  双值交换:x   =   a,   x==b;   b,   x==a//常规编码为x   =   x==a   ?   b   :a   ;    ; A1 b$ _% @1 l8 K
  1.x   =   a+b-x   ;   
  2.x   =   a^b^x   ;   
     * O9 ]4 A4 ~: W2 w9 l) c! ?
  下舍入到2的k次方的倍数:   
  1.x   &   ((-1)<<k)   
  2.(((unsigned)x)>>k)<<k   
  上舍入:    , l* {2 J0 n, f. D4 n
  1.   t   =   (1<<k)-1   ;   x   =   (x+t)&~t   ;   
  2.t   =   (-1)<<k   ;   x   =   (x-t-1)&t   ;   
     $ Y0 ?$ v& q9 N; T
  位计数,统计1位的数量:    , a$ k+ d; s5 Z' \( N
  1.   
  int   pop(unsigned   x)      J7 a, `) |4 E% J) o5 Q$ Q
  {    ; T* H5 ?5 ]6 C( T: ?
  x   =   x-((x>>1)&0x55555555)   ;    8 H" [& V2 R& i# B, H$ S# @
  x   =   (x&0x33333333)   +   ((x>>2)   &   0x33333333   )   ;    + \5 c# z3 s2 a/ s* o$ i. A
  x   =   (x+(x>>4))   &   0x0f0f0f0f   ;   
  x   =   x   +   (x>>8)   ;    - g5 F) w# w9 a7 `8 R% z: e
  x   =   x   +   (x>>16)   ;    * q; O/ `& f: h
  return   x   &   0x0000003f   ;    . l2 y" A" `6 y- n9 W+ Z
  }   
  2.   
  int   pop(unsigned   x)   {    ! g7 ^3 S, k% D$ R+ g% J! X. c5 E
  static   char   table[256]   =   {   0,1,1,2,   1,2,2,3,   ....,   6,7,7,8   }   ;   
  return   table[x&0xff]+table[(x>>8)&0xff]+table[(x>>16)&0xff]+table[(x>>24)]   ;   
  }   
     2 ]0 B- P1 T6 _5 c
  奇偶性计算:   
  x   =   x   ^   (   x>>1   )   ;    + I+ w0 o5 R1 c/ u7 g2 p
  x   =   x   ^   (   x>>2   )   ;    # F; S3 e9 F5 _2 X0 }" \2 V; H
  x   =   x   ^   (   x>>4   )   ;      K% T7 M' p8 J9 {0 ~8 n# c
  x   =   x   ^   (   x>>8   )   ;   
  x   =   x   ^   (   x>>16   )   ;   
  结果中位于x最低位,对无符号x,结果的第i位是原数第i位到最左侧位的奇偶性      `$ {7 x* F! w, o+ n6 F
    
     & u, N3 @- G5 `; f2 x) |# c
  位反转:   
  unsigned   rev(unsigned   x)      }  b3 Q8 U+ E7 U
  {   
  x   =   (x   &   0x55555555)   <<   1   |   (x>>1)   &   0x55555555   ;   
  x   =   (x   &   0x33333333)   <<   2   |   (x>>2)   &   0x33333333   ;   
  x   =   (x   &   0x0f0f0f0f)   <<   4   |   (x>>4)   &   0x0f0f0f0f   ;   
  x   =   (x<<24)   |   ((x&0xff00)<<8)   |   ((x>>8)   &   0xff00)   |   (x>>24)   ;   
  return   x   ;    - I) G% q8 N* x4 H! l, c
  }   
     + T6 k8 S* B- F* }6 o+ ?
  递增位反转后的数:   
  unsigned   inc_r(unsigned   x)   
  {   
  unsigned   m   =   0x80000000   ;   
  x   ^=   m   ;   
  if(   (int)x   >=   0   )     
  do   {   m   >>=   1   ;   x   ^=   m   ;   }   while(   x   <   m   )   ;    , z  a' x- K" p" g) O; F* C' M- x
  return   x   ;    2 f- w5 X: k- m5 l
  }   
    
  混选位:   
  abcd   efgh   ijkl   mnop   ABCD   EFGH   IJKL   MNOP->aAbB   cCdD   eEfF   gGhH   iIjJ   kKlL   mMnN   oOpP    ! k) z  R: i6 F) f
  unsigned   ps(unsigned   x)   
  {    # E/ u9 R# z6 b. M) F+ h
  unsigned   t   ;   
  t   =   (x   ^   (x>>8))   &   0x0000ff00;   x   =   x   ^   t   ^   (t<<8)   ;   
  t   =   (x   ^   (x>>4))   &   0x00f000f0;   x   =   x   ^   t   ^   (t<<4)   ;    6 z* _2 u+ Z  ?6 |- W" }
  t   =   (x   ^   (x>>2))   &   0x0c0c0c0c;   x   =   x   ^   t   ^   (t<<2)   ;    " F6 H3 v9 R+ f0 H' W) R# h0 h
  t   =   (x   ^   (x>>1))   &   0x22222222;   x   =   x   ^   t   ^   (t<<1)   ;   
  return   x   ;   
  }    4 ?% h1 F# y# U! \4 m9 C
    
  位压缩:    " l, g+ E/ O$ B  O: w  W7 q( M( a
  选择并右移字x中对应于掩码m的1位的位,如:compress(abcdefgh,01010101)=0000bdfh   
  compress_left(x,m)操作与此类似,但结果位在左边:   bdfh0000.    - T3 k2 y' K. S7 G8 V: f
  unsigned   compress(unsigned   x,   unsigned   m)   
  {   
  unsigned   mk,   mp,   mv,   t   ;   
  int   i   ;   
    
  x   &=   m   ;   
  mk   =   ~m   <<   1   ;    1 p# O  F. z8 j; z0 V  `
  for(   i   =   0   ;   i   <   5   ;   ++i   )   {   
  mp   =   mk   ^   (   mk   <<   1)   ;    : g5 Y. P$ Q. h+ M
  mp   ^=   (   mp   <<   2   )   ;   
  mp   ^=   (   mp   <<   4   )   ;   
  mp   ^=   (   mp   <<   8   )   ;   
  mp   ^=   (   mp   <<   16   )   ;    ) |; V1 F* [6 h* O1 T. b" X
  mv   =   mp   &   m   ;   
  m   =   m   ^   mv   |   (mv   >>   (1<<i)   )   ;   
  t   =   x   &   mv   ;   
  x     =   x   ^   t   |   (   t   >>   (   1<<i)   )   ;    9 [. {6 d$ M6 Q* B3 f# h) {
  mk   =   mk   &   ~mp   ;   
  }    * y2 }- |8 K; v' h/ c
  return   x   ;    : q4 R% k% k. x! z. Y* ?6 d  a
  }    * W* x3 E2 C! m/ W
    
    
  位置换:   
  用32个5位数表示从最低位开始的位的目标位置,结果是一个32*5的位矩阵,   
  将该矩阵沿次对角线转置后用5个32位字p[5]存放。   
  SAG(x,m)   =   compress_left(x,m)   |   compress(x,~m)   ;    : y  m9 I: B- `" L. S3 \) F
  准备工作:    ! t: k* f; @* f8 l$ h( N7 R
  void   init(   unsigned   *p   )   {   
  p[1]   =   SAG(   p[1],   p[0]   )   ;   
  p[2]   =   SAG(   SAG(   p[2],   p[0]),   p[1]   )   ;    7 h( w  _/ I" ]- U% l
  p[3]   =   SAG(   SAG(   SAG(   p[3],   p[0]   ),   p[1]),   p[2]   )   ;   
  p[4]   =   SAG(   SAG(   SAG(   SAG(   p[4],   p[0]   ),   p[1])   ,p[2]),   p[3]   )   ;    ! c1 O7 A/ Y) z! i  p+ Y6 _9 G
  }   
  实际置换:   
  int   rep(   unsigned   x   )   {    & D$ {3 m: \# k6 G: p! X
  x   =   SAG(x,p[0]);    / I! x2 F/ F: N+ j
  x   =   SAG(x,p[1]);   
  x   =   SAG(x,p[2]);      g4 N9 [8 ?  x5 o
  x   =   SAG(x,p[3]);   
  x   =   SAG(x,p[4]);   
  return   x   ;    6 S% T# X& M9 [- |% W$ k6 V! G
  }    ) }7 w% j. K/ x* V+ w* M7 i
     9 v( V2 u3 S3 l8 s( [4 R' w/ Q
  二进制码到GRAY码的转换:   
  unsigned   B2G(unsigned   B   )    ! ?5 \+ K+ ]) p4 Y5 V
  {   
  return   B   ^   (B>>1)   ;   
  }   
  GRAY码到二进制码:    $ B4 e; R0 j! B% }, \1 N2 @
  unsigned   G2B(unsigned   G)   
  {   
  unsigned   B   ;   
  B   =   G   ^   (G>>1)   ;   
  B   =   G   ^   (G>>2)   ;   
  B   =   G   ^   (G>>4)   ;    * o2 n0 [8 j1 A+ E, I: T  m
  B   =   G   ^   (G>>8)   ;   
  B   =   G   ^   (G>>16)   ;    * }8 {6 ^2 D6 n) s$ _2 H" n
  return   B   ;   
  }    # ^* c* }; s4 _# O! j# ^- e' |
    
  找出最左0字节的位置:   
  int   zbytel(   unsigned   x   )    ' z. O5 z, z) \6 Y) C+ q
  {    . }  m$ }$ r7 e" y6 m! @6 [
  static   cahr   table[16]   =   {   4,3,2,2,   1,1,1,1,   0,0,0,0,   0,0,0,0   }   ;    3 ~* v' m: C: h$ V1 J% r% @
  unsigned   y   ;   
  y   =   (x&0x7f7f7f7f)   +   0x7f7f7f7f   ;   
  y   =   ~(y|x|0x7f7f7f7f)   ;    ; C$ m6 }* w# ?% C7 d2 v
  return   table[y*0x00204081   >>   28]   ;//乘法可用移位和加完成    * M' t. J. N1 C4 O  [/ b0 y% B
  }

在第一节概述里就说了,C语言是一种中级语言,能对计算机硬件直接操作,这就涉及到位的概念。

一、位的概念
    我们知道,在计算机中,一字节占8位(现在的某些电脑也有占16位的),这样表示的数的范围为0-255,也即00000000-11111111。位就是里面的0和1。
        char c=100; 9 l& Q4 H7 y4 B; b( j% ?
    实际上c应该是01100100,正好是64H。其中高位在前,低位在后。                       |             | % |- W* E. e, b) D, q5 m, S
                           第7位   第0位

二、位逻辑运算符 ( G) _& G: z9 a+ n6 I2 E5 Z

        符号         描述
         &           位逻辑与
         |           位逻辑或
         ^           位逻辑异或
         ~           取补 $ m0 L9 L! h1 S1 `
9 z* r  v3 Z8 Y" V
    表中除去最后一个运算符是单目运算符,其他都是双目运算符。这些运算符只能用于整型表达式。位逻辑运算符通常用于对整型变量进行位的设置、清零、取反、以 及对某些选定的位进行检测。在程序中一般被程序员用来作为开关标志。较低层次的硬件设备驱动程序,经常需要对输入输出设备进行位操作。  ! E  K( ^1 Q0 W7 e) U5 \
3 k  B) m6 s3 y! |7 _) k: ]
         & 运算的规则是当两个位都为1时,结果为1,否则为0;
         | 运算的规则是当两个位都为0时,结果为0,否则为1;
         ^ 运算的规则是当两个位相同时,结果为0,否则为1; 6 ]2 f$ ^/ {; A9 R' E% k( A4 R6 H2 ?
         ~ 运算的规则是当为1时结果为0,当为0时,结果为1。

    设置位:设置某位为1,而其他位保持不变,可以使用位逻辑或运算。
        char c;
        c=c|0x40; 3 ~' d3 r  l: [" r: K
    这样不论c原先是多少,和01000000或以后,总能使第6位为1,而其他位不变。 % ]  u' J: M. Y2 c5 `
1 w; `4 U; `, n$ z. V# Q) c9 ^
    清除位:设置某位为0,而其他位保持不变。可以使用位逻辑与运算。 + A# }6 X1 K* T1 n/ h
        c=c&0xBF; 8 C* r8 C: r0 {
    这样c和10111111与以后,总能使第6位为0,其他位保持不变。 7 x2 M8 [! n% G
    那如果想让某位为1,其他位都为0怎么办呢? 4 R& e$ i: ]+ U/ C
9 T, u$ a9 Y" Q6 Q7 v
三、位移运算符
         符号             描述 6 r; b% e$ o1 E" D2 ]- B
          <<              左移
          >>              右移 ; N- d6 Q7 r, g- U/ _9 E# e

    位移运算符作用于其左侧的变量,其右侧的表达式的值就是移动的位数,运算结果就是移动后的变量结果。
        b=a<<2;
    就是a的值左移两位并赋值为b。a本身的值并没有改变。 8 C; w9 B2 d. j( `; P
                 6 p6 c  U) ]0 ]% {8 p) j
    向左移位就是在低位沙锅补0,向右移位就是在高位上补0。右移时可以保持结果的符号位,也就是右移时,如果最高位为1,是符号位,则补1而不是补0。
    程序员常常对右移运算符来实现整数除法运算,对左移运算符来实现整数乘法运算。其中用来实现乘法和除法的因子必须是2的幂次。 $ j4 h% i1 E3 P' y- \( p

    举例:输入一个整数,判断这个数中有几个二进制位1?例如输入67,输出结果应该为3。因为67的相应二进制数为00000000 01000011(0043H),有3个1出现。
    分析:要判断是不是1,只需要判断该位与1与以后是不是1就可以知道。一个整数,判断16次即可。 , }5 ?2 e% G0 D; ^" t# R
+ F& ]4 l$ t7 \8 d* X
        main() 6 t- w; P0 }! L& u# x! y5 M
        { 5 c# I9 `: z+ A& L* h& H
            int num,k;
            int count=0;               /* 记录1的个数 */ 0 q9 y+ N$ M- |- B$ r1 [
            scanf(\"%d\",&num);
            for(k=0;k<16;k++)
            {
                if(num&1==1) count++;    /* 判断最低位是不是1 */
                num>>=1;                 /* num右移1位 */ 

               } 3 I) }( u6 p( x7 ?5 w# \4 o& x
             printf(\"%d\\n\",count); 3 b$ x$ R& z. q3 P* o
        } - i) p; D/ X* V5 I2 j- x

    这样每次都判断最低位是不是1,判断完以后,让前面的右移一位即可。 + K- g9 E" v; B7 K9 D' E
    对位的操作,一般程序中用的不多,但是在对计算机硬件操作时,肯定会涉及到。例如,我们以后要讲到的对串口和声卡操作就要用到一些。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值