文章目录
新知
- 如果左移n位,就相当于在原来的基础上乘以 2的n次方
- %d 输出
0xffff ffff
,输出为-1
.
%u 输出0xffff ffff
,输出为4294967295
. - 右移的补位
如果x是signed ,那么高位全部补符号位
如果x是unsigned,那么高位全部补0
char c = -56 >> 30;//右移30位后得:0xffff ffff。强制转换位char,c = 0xff;
printf("%d\n",c);//%d表示有符号整型输出,0xffff ffff 是-1的补码,所以输出-1
printf("%u\n",c);//%u表示无符号整型输出,0xffff ffff = 4294967295
//-56u 表示把 -56整型数 转换为 无符号整型数
char c = -56u >> 30;//-56 在计算机存储的格式是补码: 0xffffffc8;右移30位,无符号右移高位补0,然后强制转换位char型:0x03
printf("%d\n",c);//0x03 = 3
printf("%u\n",c);//0x03 = 3
- 异或
与1异或即取反
与0异或就是本身
利用 异或的交换律 实现无中间变量 互换变量值 - 逗号运算符
最后的表达式才是结果 - 作业题目!!!
将x(int)中第m位开始的连续n个bit位取反,其余各位保持不变
0. sizeof()是运算符,也是关键字
1. C语言取整数
取整风格共有3种:
向零取整。即向坐标轴0的方向,取最近的整数。
向上取整。也就是向+∞取整,即取不小于结果的最小整数。
向下取整。也就是向-∞取整,即取不大于结果的最大整数。
所以,C语言中计算-5除以3,因为实数结果约为-1.67,向零取整,得到结果为-1。
2. 负数取余
#include <iostream>
using namespace std;
int main()
{
cout<<(5%3)<<endl; //5=3x1+2
cout<<(-5%-3)<<endl; //-5=-3x1-2
cout<<(5%-3)<<endl; //5=-3x(-1)+2
cout<<(-5%3)<<endl; //-5=3x(-1)-2
system("pause");
return 0;
}
3. 异或的妙用
与1异或即取反
与0异或就是本身
^ 按位异或
求异,不同为1,相同为0
a和b都是1bit
a b a^b
0 0 0
0 1 1
1 0 1
1 1 0
通过上面可以得出结论:
1,一个bit位与1进行 ^ 运算,结果是 取反
a ^ 1 -> ~a
2,一个bit位与0进行 ^ 运算,结果是 它本身
a ^ 0 -> a
利用 异或的交换律 实现无中间变量 互换变量值
练习:
有两个整型变量 a,b;
a ^ b ^ a -> b
^满足“交换律”,那么a ^ b ^ a 等价 a^a^b
a ^ a -> 0
0 ^ b -> b
---------------------------------------------
交换两个int型数据 a,b的值,不能使用其他变量
a b
a = a + b; a+b b
b = a - b; a+b a+b-b=a
a = a - b; a+b-a=b a
----------------------------------------------
a = a^b; a^b b
b = a^b; a^b a^b^b = a
a = a^b; a^b^a=b a
4. 左移/右移
例子:
123 << 4 -> 1968
000..0000 0111 1011 << 4
1*2^0 + 1*2^1 + 1*2^3 + 1*2^4 + 1*2^5 + 1*2^6
00..000111 10110000 -> 1968
1*2^4 + 1*2^5 + 1*2^7 + 1*2^8 + 1*2^9 + 1*2^10
->
2^4*(2^0+1*2^1 + 1*2^3 + 1*2^4 + 1*2^5 + 1*2^6 )
结论:如果左移n位,就相当于在原来的基础上乘以 2的n次方。前提是高位丢弃的全是0
按位右移
x >> n 把x按bit位整体往右移动n bit位
低位右移后,直接丢弃
高位补什么?
如果x是signed ,那么高位全部补符号位
如果x是unsigned,那么高位全部补0
123 >> 3
000..0000 0111 1011 >> 3
000000..0000 0111 1 ->15
练习:
1,假设一个int型变量 a,要把a的bit n变为1,其他Bit保持不变
a = (1<<n) | a
2,假设一个int型变量 a,要把a的bit n变为0,其他Bit保持不变
111111101111111
~000000010000000
a = ~(1<<n) & a
负数右移
printf("%d\r\n", -6>>2);//-2
printf("%d\r\n", -9 >> 2);//-3
-6>>2
在32位系统中,首先-6的二进制形式是1000 0000 0000 0110
,
- 反码是
1111 1111 1111 1001
, - 补码是反码+1:
1111 1111 1111 1010
,其十六进制是fffa
,由下图可知负数在计算机中是以补码的形式保存的。 - -6右移2位,得到
1111 1111 1111 1110
.(注意:有符号数右移补符号位,系统默认整数常量为signed int 型,故这里右移补符号位1) - 右移的结果取反+1转化为原码:
1000 0000 0000 0010
= -2.
5. 逗号运算符
,
双目运算符,优先级最低,结合性从左到右
语法: 表达式1,表达式2,表达式3,,,,,,,,,表达式n
逗号表达式的运算顺序是:先求表达式1的值,再求表达式2的值,......最后求表达式3的值
整个逗号表达式的值为最右边的那个表达式的值。
例子:
3+6,7*9,5/2 ->这个逗号表达式的值为2
int main()
{
int a;
a = 3 + 6, 7 * 9, 5 / 2;//逗号表达式,逗号运算符优先级最低,一开始就先赋值了
printf("a=%d\n", a);//9
a = (3 + 6, 7 * 9, 5 / 2);//用括号括起来,先做逗号运算得到5/2=2,再做赋值运算 a = 2
printf("a=%d\n", a);//2
}
6. 逻辑运算符有短路特性
&&、||运算符短路特性
int a = 1, b = 2, c = 3, d = 4;
int m = 1, n = 1;
(m = a > b) &&(n = c > d);//逻辑运算&&左边为假,右边的不用运算了
printf("m = %d\tn = %d\n", m, n);//m = 0 n = 1
(m = a > b) ||(n = c > d);//逻辑运算||左右两边都有运算
printf("m = %d\tn = %d\n", m, n);//m = 0 n = 0
7. 赋值运算符的拓展是自右向左
int main()
{
int a = 1;
a += a *= a += 3;//自右向左,a = a+3 = 4; a = a*4 = 16; a = a + 16 = 32;
printf("a:%d\n", a);//a:32
}
8. 位运算(与底层打交道)
>> 、<<、 ~、 | 、&、 ^ 、
~
表示按位取反,注意不要用成!
num |= 1<<n;//将操作数中第n位置1,其他位不变
num &= ~(1<<n);//将操作数中第n位清0,其他位不变
- 将操作数中的第n位置1,其他位不变:
num = num |1<<n;
- 将操作数中的第n位置0,其他位不变:
num = num &~(1<<n);
- 测试第n位:
if(num & 1<<n)
- 将x(int)中第m位开始的连续n个bit位取反,其余各位保持不变
x = (((1<<n)-1)<<m) ^ x;
- 将x中的第m位开始的n个bit位设置为y中的最右边的n个bit的值,x的其余各位保持不变
作业
常出错:
%d 输出 ffff ffff
,输出为-1
.
%u 输出 ffff ffff
,输出为4294967295
.
作业
1. 将x(int)中第m位开始的连续n个bit位取反,其余各位保持不变
int main()
{
int x = 255;
int m = 1;//第1为开始
int n = 4;//连续4位
int i;
printf("%x\r\n", x);
x = (((1<<n)-1)<<m) ^ x;
printf("%x\r\n", x);
}
2,将x中的第m位开始的n个bit位设置为y中的最右边的n个bit的值,x的其余各位保持不变
int main()
{
int x = 255;//1111 1111
int y = 30;//0001 1110
int m = 1;//第1为开始
int n = 4;//连续4位
x = x & (~(((1 << n) - 1) << m));//把x中对应的位清0
printf("%x\r\n", x);
y = y & ((1 << n) - 1);//取y中的m bit
x = x | (y << m);//把y填入x中
printf("%x\r\n", x);
((y & ((1 << n) - 1)) << m) | (~(((1 << n) - 1) << m) & x);
}
3.分析如下程序的输出结果
char c = -56 >> 30;
负数的补码:绝对值的原码取反加一
0000..000000111000
1111..111111000111
1111..111111001000 >> 30
111..1111...1111
11111111
printf("%d\n",c);
printf("%u\n",c);
----------------------
char c = -56u >> 30;
printf("%d\n",c);
printf("%u\n",c);