高效“神奇”的位操作符

& |^ ~ << >>

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

左移运算,空位都用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}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值