现在的位置: 首页 > 综合 > 正文

高效“神奇”的位操作符

2017年12月15日 ⁄ 综合 ⁄ 共 2610字 ⁄ 字号 评论关闭

位操作符

& |^ ~ << >>

只能用于整数,其中<<>>操作符是双目操作符,它们的右操作数必须为非负整数;

左移运算,空位都用0填充;

右移运算,unsigned类型空位用填充,signed类型空位有的用0填充,有的用符号位填充,取决于具体实现;

功能                              示例                           位运算           

去掉最后一位               (101101->10110)              
x >> 1           

在最后加一个0            
(101101->1011010)
            x << 1           

在最后加一个1            
(101101->1011011)
            x << 1+1         

把最后一位变成1          
(101100->101101)
              x | 1           

把最后一位变成0         
(101101->101100)
               x | 1-1         

最后一位取反               (101101->101100)              
x ^ 1           

把右数第k位变成1         
(101001->101101,k=3)
        x | (1 << (k-1)) 

把右数第k位变成0         
(101101->101001,k=3)
        x
& ~ (1<< (k-1))

右数第k位取反             
(101001->101101,k=3)
        x ^ (1 << (k-1)) 

取右数第k位                
(1101101->1,k=4)
              x >> (k-1) & 1   

取末三位                      (1101101->101)                
x & 7           

取末k位                      
(1101101->1101,k=5)
         x & (1 << k-1)  

把末k位变成1                
(101001->101111,k=4)
        x | (1 << k-1)  

k位取反                    
(101001->100110,k=4)
        x ^ (1 << k-1)  

把右边连续的1变成0        
(100101111->100100000)
     x & (x+1)       

把右起第一个0变成1        
(100101111->100111111)
     x | (x+1)       

把右边连续的0变成1        
(11011000->11011111)
        x | (x-1)       

取右边连续的1               
(100101111->1111)
           (x ^ (x+1)) >> 1 

去掉右起第一个1的左边     (100101000->1000)          
x & (x | (x-1))   

取全1~0

末尾取11 << k-1

强制赋值1|

强制赋值0&

使用移位运算符时, 如果被移位的对象的长度为n,那么移位计数必须大于或者等于0,而且要严格小于n

考虑一个比较流行的不使用临时变量交换两个数的函数语句

(*a) ^= (*b) ^= (*a) ^= (*b);

整个语句位于两个序列点之间,并且两次修改了同一变量,所以这个语句是不可移植的,标准视其为未定义的。

可以使用替代的写法:

(*a) ^= (*b);

(*b) ^= (*a);

(*a) ^= (*b);

实际是是利用了^运算的逆运算是它自身的这个特点

(*a) = (*a) # (*b);

(*b) = (*a) @ (*b);

(*a) = (*a) @ (*b);

(通法:其中#@互为逆运算)

例如:

(*a) += (*b);

(*b) = (*a) -(*b);

(*a) -= (*b);

    1#include
<stdio.h>

    2

    3intmain(void)

    4{

    5    printf("%d\n\n",
~
3+1);                   /*取反加1得到相反数*/

    6

    7    printf("%d\n",
~
0);

    8    printf("%d\n",
(
unsigned int) ~0);

    9    printf("%u\n",
(
unsigned int) ~0);

   10    printf("%d\n",
( (
unsigned int) ~0)
>>
1);

   11    printf("%u\n",
( (
unsigned int) ~0)
>>
1);

   12    printf("%d\n\n\n",
(
int) ( ( (unsigned
int
) ~0)
>>
1) );

   13    

   14    printf("%d\n",
~
0);

   15    printf("%d\n",
(
unsigned char) ~0);

   16    printf("%u\n",
(
unsigned char) ~0);

   17    printf("%d\n",
( (
unsigned char) ~0)
>>
1);

   18    printf("%u\n",
( (
unsigned char) ~0)
>>
1);

   19    printf("%d\n",
(
char) ( ( (unsigned
char
) ~0)
>>
1) );

   20

   21

   22    

   23    /*

   24    
* * * %d
格式取32位输出,最高位为符号位,当右移一位时,去除了符号位,输出时显示为正整数(31位)

   25    
* * * %u
格式也是取32位输出,没有符号位,右移一位后,输出时显示31位正整数

   26    
* * *
当强制转换为unsigned int时,取32位,并将最高位的符号性质抹去

   27    
* * *
当强制转换为unsigned char时,取8位,无所谓符号位(以%d或者%u打印时,最高位在32位)

   28    
*/

   29    return0;

   30}




抱歉!评论已关闭.