C语言位运算

最近上计算机系统cs213,这周的作业就需要用到很多奇奇怪怪的位运算,我觉得真的很难啊...所以补一下相关知识。

首先,我们都知道三个逻辑运算符,&&代表逻辑与,||代表逻辑或,!代表单目逻辑非。

(Plus,如果对一个数字进行两次单目逻辑非,得到的是其逻辑值)

int a=10,b=0;

cout<<"We use 1 to denote truth and 0 to denote false"<<endl;
cout<<"(5<a)&&b is:"<<((5<a&&b))<<endl;

然后我们再看看为逻辑运算符和位逻辑表达式:

位运算算是C语言的特色内容了,位运算可以实现位的设置、清零、取反、取补操作。利用位运算可以实现只有部分汇编语言才能实现的功能。

位逻辑运算符:

& 代表 按位逻辑与
| 代表 按位逻辑或
^ 代表 按位 异或
~ 代表 按位取反        唯一一个单目运算符,以上都是双目运算符

我们假设A是60 (A = 0011 1100)
<<	二进制左移运算符。左操作数的值向左移动右操作数指定的位数。A << 2 将得到 240,即为 1111 0000
>>	二进制右移运算符。左操作数的值向右移动右操作数指定的位数。A >> 2 将得到 15,即为 0000 1111

程序中,位逻辑运算符一般被我们用作开关标志。较低层次的硬件设备驱动程序经常需要对I/O设备进行位操作。

我们举个例子来康康:

#include <iostream>
using namespace std;
 
int main()
{
   unsigned int a = 60;      // 60 = 0011 1100  
   unsigned int b = 13;      // 13 = 0000 1101
   int c = 0;           
 
   c = a & b;             // 12 = 0000 1100
   cout << "Line 1 - c 的值是 " << c << endl ;
 
   c = a | b;             // 61 = 0011 1101
   cout << "Line 2 - c 的值是 " << c << endl ;
 
   c = a ^ b;             // 49 = 0011 0001
   cout << "Line 3 - c 的值是 " << c << endl ;
 
   c = ~a;                // -61 = 1100 0011
   cout << "Line 4 - c 的值是 " << c << endl ;
 
   c = a << 2;            // 240 = 1111 0000,*4
   cout << "Line 5 - c 的值是 " << c << endl ;
 
   c = a >> 2;            // 15 = 0000 1111,看似是/4,但其实说不清楚
   cout << "Line 6 - c 的值是 " << c << endl ;
 
   return 0;
}

在进行右移操作时对于有符号数需要注意符号位的问题,如果是+数,符号位为0;为负数的时候,最高位置是补0还是补1取决于编译系统的规定,移入0进去的话为逻辑右移,1的话为算术右移。大部分机器都是算术右移的。

 

(说得比较模糊,这么讲:

首先说明一下这两个概念: 
逻辑右移:右移后左边添加0 
算术右移:右移后添加的位与原数的符号位相同

C语言中,对于移位操作执行的是逻辑左移和算术右移不过对于无符号类型,所有的移位操作都是逻辑的。 

)

 

可以举个例子来康康:

可见,在dev-C++上的默认编译器上,-30右移动三位得到-4,是采取算术右移方式。用2进制表示,前面30位都是1,后面两位是0,算出来这个x>>3=-最高位位权+其余位位权*位的值,就等于-{1+2(+1)}=-4。

 

我们再看看循环移位:

顾名思义,循环移位就是将将移除的低位放到高位,移除的高位放到低位,有点像...循环链表?

我们这里稍微介绍一下循环左移:(高位向左出“栈顶”,回归“栈底”)。

比如对x串,向左循环左移n位:
首先将x的左端n位,在位串内部向右移动,我们假定这台机器里面int占4个字节(小声哔哔
z=x>>(32-n);

然后将x左移n位,右边补零:
y=x<<n;

最后将y、z按位“或”运算

y=y|z;

啊哈,大功告成

我们具体实现一下循环左移:从键盘中读入一个八进制数,然后输入想要移位的位数,最后循环左移的结果打印在控制台上。

#include <stdio.h>
LeftShift(unsigned value,int n)
{
    unsigned z;
    z=(value>>(32-n)|(value<<n));
    return z;
}

int main()
{
    unsigned a;
    int n;
    printf("hey  boy,please input an octal number in here:\n");
    scanf("%o",&a);
    printf("hey boy,please input the number of leftshift displacement:\n");
    scanf("%d",&n);
    printf("The result is shown below:\n %o in octal form",LeftShift(a,n));
    return 0;
}

而循环右移和循环左移是一个道理,不予赘述。

位段我们就先不介绍了,如有必要再另行补充。

补充一:

a&b 9&8 
1001 
1000
结果是1000 
而a&&b 9&&8 结果是1

补充二:

1.十进制:除表示正负的符号外,以1~9开头,由0~9组成。如,128,+234,-278。
2,八进制:以0开头,由0~7组成的数。如,0126,050000.
3,十六进制:以0X或0x开头,由0~9,A~F或a~f 组成。如,0x12A,0x5a000.

——————————————————————————————————————————作业中最简单的一道练习题:

假设我们将一个w位的字中的字节从0(最低位)到w/8 -1(最高位)编号,写出下面的C函数的代码,他会返回一个无符号的值,其中参数x的字节i被替换成字节b:

比如,从第0个字节移到第一个字节,需要移动8位,而从第零个字节到第i个字节,就要移动i<<3=i*2^3=8*i位。

unsigned replace_byte(unsigned x,int i,unsigned char b);

//form:
replece_byte(0x12345678,2,0xAB) -->0x12AB5678
replace_byte(0x12345678,0,0xAB) -->0x123456AB

//solution:
unsigned replace_byte(unsigned x, unsigned char b, int i)
{
    return (x & ~(0xFF<<(i<<3))) | (b << (i<<3));  //(i<<3可以写成8*i)
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值