"&"符号你知道多少

对于学习c/c++的人来说,都应该知道这个符号的,如果你连这个运算符都不知道,可以说你压根就没有学过c/c++,虽然这个符号大家都知道是按位与运算符,但是很多时候看到别人的代码里面有这个运算的时候,就感觉别人的代码好难懂,好难理解。不信就来几段实际的代码看看。

int count(unsigned char n)
{
   
intsum=0;
   
while(n)
    {
        n&=(n-
1);
        sum++;
    }
   
returnsum;
}

         对于稍微有点经验的人都知道这段代码是干什么用的,但是对于很多人我相信还是不知道这段代码是干什么用的,当然还有一部分人知道这段代码是干什么用的,但是说不出来为什么这段代码就能够实现那个功能。接下来我就简单的说一下这段代码。高手不要笑话,如果有错误的地方,还请多多指正。

         首先我第一次看到这段代码的时候,是在一套笔试题里面,然后我当时不知道这段代码的作用,后来到网上查了一下,知道这是微软的一套笔试题,这个函数是用来统计n的二进制表示里面1的个数的。当时怎么也想不明白,为什么这样就可以计算出n的二进制里面1的个数。首先给出两个位运算满足的定理!

         定理1:对于任意的同类型的两个整形数据x,y,必定满足x&y<=x,当然也满足x&y<=y

 

         证明:对于任意的X,肯定可以表示为X=a1*2^31+a2*2^30+…+a32*2^0.其中a1,a2…,a32的取值为0或者1,同理Y=b1*2^31+b2*2^30+…+b32*2^0.

因此X&Y=(a1&b1)*10^31+(a2&b2)*10^30+…+(a32&b32)*10^0.因为a1a32b1b32的取值都为0或者1,同时与运算的规则为:0&0=0,1&1=1,0&1=0,1&0=0;因此可以肯定的得出,

a1&b1<=a1,a1&b1<=b1,因此可以x&y<=xx&y<=y

 

定理2:对于一个无符号非0的整形数据XX对应的二进制序列a1,a2,a3…a32X-1对应的二进制序列b1,b2,b3…b32.存在一个整数p1<=p<=32,满足ap>ai,(i>p,i<=32),对于p,一定满足ap&bp=0;

 

对于定理2的描述很复杂,用通俗的话讲,就是对于一个无符号的非零整形数据XX的二进制序列里面最右边为1的那一位,在X-1中该对应的位一定为0.

对于定理2的证明描述起来较为复杂就不写了。当然有兴趣的同学也可以下去自己证明。不会证明的也不重要,只要记住这个结论就可以了。

 

有了定理2,我们在返回来看上面的那段代码就比较容易弄明白了。X=x&(X-1)实际上是将X的二进制序列里面最右边的1变为了0,因此循环下去就可以计算出最开始X的二进制里面1的个数。

 

当然对于定理2里面的一些在代码里面的特殊应用。

比如判断一个数是不是2n次幂。经过分析,一个数是x,如果是2n次幂,那么x的二进制序列里面肯定只有一个位为1,因此x&(x-1)必定为0.这个通常可以用来判断一个数是不是2n次幂。函数代码可以精炼到下面的情况:

bool foo(unsigned int x)

{

         return(0==x&(x-1));

}

 

当然如果一个x2n次幂,那么x的二进制序列里面只有一位为1,假定第p位为1,那么x-1的二进制序列一定满足从第p+1位到末尾全都为1,这个自己想一想就能够明白。因此对于任意的一个整型数y,y&(x-1)的值和y%x的值相同。只有明白了这个道理才能看明白下面的代码。

 

这段代码是通过环形缓冲区实现的队列,代码很精炼。当然不是我写的,我是在网上看到的,拿到这段代码的时候,没有任何注释,然后自己看明白了,添上了一部分注释。也是在看这段代码的时候,总结出了上面的一些东西。其实我个人猜想stl里面的队列应该也是用的这个原理,当然他的功能更强大,但是基本思想肯定和这个一样的。

 

环形缓冲区实现的队列代码:

#include <stdio.h> 

#include <stdlib.h> 

#include <string.h> 

#include <unistd.h> 

#include <pthread.h> 

 

#define BUFFSIZE 1024 * 1024 

#define min(x, y) ((x) < (y) ? (x) : (y)) 

 

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 

 

//环形缓冲区结构体定义

struct cycle_buffer { 

    unsigned char *buf; 

    unsigned int size; 

    unsigned int in; 

    unsigned int out; 

    pthread_mutex_t lock; 

}; 

 

//环形缓冲区全局的指针

static struct cycle_buffer *fifo = NULL; 

 

//初始化环形缓冲区

static int init_cycle_buffer(void) 

{

    int size = BUFFSIZE,ret; 

 

    ret = size & (size -1);   //判断size是不是2n次幂,如果是ret0,否则不为0

    if (ret)

        return ret;

    fifo = (structcycle_buffer *) malloc(sizeof(struct cycle_buffer));   //分配缓冲区对象

    if (!fifo) 

        return -1; 

 

    memset(fifo, 0,sizeof(struct cycle_buffer));   //填充为0

    fifo->size = size;   //初始化缓冲区大小

    fifo->in = fifo->out= 0;   //初始化读写下标

   pthread_mutex_init(&fifo->lock, NULL);  //初始化锁

    fifo->buf = (unsignedchar *) malloc(size);  //分配缓冲区大小

    if (!fifo->buf)

        free(fifo);

    else

        memset(fifo->buf,0, size);  //缓冲区设置为0

    return 0; 

 

//读缓冲区

unsigned int fifo_get(unsigned char *buf, unsigned int len) 

    unsigned int l;

         //求得此次能实际够读取数据的长度

    len = min(len, fifo->in- fifo->out);  

         //由于fifo->size是一个2n次幂的数,因此

         //fifo->out&(fifo->size-1)fifo->out%fifo->size的值相同

         //那么fifo->size-(fifo->out& (fifo->size-1))就是读数据下

         //标到缓冲区末尾的长度,后面的就容易理解了

    l = min(len, fifo->size- (fifo->out & (fifo->size - 1))); 

         memcpy(buf,fifo->buf + (fifo->out & (fifo->size - 1)), l); 

    memcpy(buf + l,fifo->buf, len - l); 

    fifo->out += len;

        

    //返回实际读取的数据的长度

         return len; 

 

//写缓冲区

unsigned int fifo_put(unsigned char *buf, unsigned int len) 

    unsigned int l; 

    len = min(len,fifo->size - fifo->in + fifo->out); 

    l = min(len, fifo->size- (fifo->in & (fifo->size - 1))); 

    memcpy(fifo->buf +(fifo->in & (fifo->size - 1)), buf, l); 

    memcpy(fifo->buf, buf +l, len - l); 

    fifo->in += len; 

    return len; 

 

static void * thread_read(void *arg) 

    char buf[1024]; 

    unsigned int n; 

   pthread_detach(pthread_self()); //线程分离

    for (;;) { 

        memset(buf, 0,sizeof(buf)); 

       pthread_mutex_lock(&fifo->lock); 

        n = fifo_get(buf,sizeof(buf)); 

       pthread_mutex_unlock(&fifo->lock); 

        write(STDOUT_FILENO,buf, n); 

    }

    printf("nnafterthread_read : %snn",buf);

    return NULL; 

 

static void * thread_write(void *arg) 

    unsigned char buf[] ="hello world"; 

   pthread_detach(pthread_self()); 

    for (;;) { 

       pthread_mutex_lock(&fifo->lock); 

        fifo_put(buf,strlen(buf)); 

       pthread_mutex_unlock(&fifo->lock);  

    } 

    return NULL; 

 

int main(void) 

    int ret; 

    pthread_t wtid, rtid; 

    ret =init_cycle_buffer(); 

    if (ret == -1) 

        return ret; 

 

    pthread_create(&wtid,NULL, thread_write, NULL); 

    pthread_create(&rtid,NULL, thread_read, NULL); 

    pthread_exit(NULL);  //保证主线程退出了,子线程还是能够运行

    return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值