位运算:
特点:速度非常快,如果能在程序中合理使用将大大提高程序运行速度
& 与:只有两个都是1才是1,否则为0
可以把某些位清0且同时保留其他位不变,也可以用来获取某变量中的一位。
eg:
将int型低8位全置成0,其余位不变:
n = n & 0xffffff00 或者n &= 0xffffff00
如果n是short类型:
n &= 0xff00
如何判断一个int型变量n的第7位(从右往左,0开始数)是否为1?
n& 0x80 == 0x80
0x80 = 1000 0000
| 或:只要有一个是1就是1,否则为0
通常用来将变量中的某些位置1且保持其他位不变
eg:
n |= 0xff
0xff: 1111 1111
^ 异或:不相同为1,相同为0
可以用来将变量中的某些位取反,且保留其他位不变。
异或运算的特点是:
- 如果a ^ b = c, 那么就有c ^ b = a以及c ^ a = b(穷举法可证)
可以用来进行最简单的加密和解密。 - 异或运算还能实现不通过临时变量,就能交换两个变量的值:
int a = 5, b = 7;
a = a ^ b;//c = a ^ b
b = b ^ a;//b ^ c = a
a = a ^ b;// c ^ a = b
即实现ab值交换,穷举法可证
eg:
只把后8位取反,前面的其他位不变
n ^= 0xff
对于后8位:1和1异或为0, 0和1异或为1
对于前面的位:1和0异或为1,0和0异或为0
~ 非:0变1, 1变0
<< 左移:a<<b, 将a各二进制全部左移b位后得到的值,左移时,高位丢弃,低位补0,a的值不因运算而改变
左移1位相当于乘2,左移n位相当于乘以2^n。而左移操作比乘法操作快得多。
>> 右移:a>>b, 将a各二进制全部右移b位后得到的值,右移时,低位丢弃,a的值不因运算而改变。对于有符号数,比如long, int, short, char类型变量,往右移时,符号位将一起移动,而且大多数C/C++编译器规定,如果原符号位为1,则右移时高位就补充1,原符号位为0,则右移高位就补充0.
右移n位相当于左操作数除以2^n,并且将结果往小里取整
eg:
-25 >> 4 = -2
-2 >> 4 = -1
18 >> 4 = 1
#include<stdio.h>
int main()
{
int n1 = 15;
short n2 = -15;
unsigned short n3 = 0xffe0;
char c = 15;
n1 >>= 2;
n2 >>= 3;
n3 >>= 4;
c >>= 3;
printf("n1=%d, n2=%x, n3=%x, c=%x", n1, n2, n3, c);
//n1 = 3, n2 = fffffffe, n3 = ffe, c = 1
}
int n1 = 15;
0000 0000 0000 0000 0000 0000 0000 1111
/>>2: 0000 0000 0000 0000 0000 0000 0000 0011 变成3
short n2 = -15;
1111 1111 1111 0001
/>>3: 1111 1111 1111 1110 变成fffffffe,即-2
unsigned short n3 = 0xffe0;
1111 1111 1110 0000
/>>4: 0000 1111 1111 1110 变成ffe
char c = 15;
0000 1111
/>>3: 0000 0001 变成1
有两个int型的变量a和n(0<= n <=31),要求写一个表达式,使该表达式的值和a的第n位相同:
答案:(a>>n)&1
如果n的范围是0<= n <31
还有一个答案:(a & (1 << n))>>n
为什么这个答案不适用于n = 31的情况:
因为 1 << n 得到的是一个第31位为0的数,如果a的31位也刚好是1的话,那么(a & (1 << n))的31位就会变成1,也就是符号位为1,这样右移的时候左边会全部都是1,而不是0,最后的结果也就不会只是31位了。
eg: a = 1000 0000 0000 0000 0000 0000 0000 1111, n = 31,表达式期待的结果是1,但是最后的结果是1111 1111 1111 1111 1111 1111 1111 1111
引用
下面的写法定义了一个引用,并将其初始化为引用的某个变量。
类型名&引用名=某类型名
某个变量的引用等价于这个变量,相当于改变量的一个别名。
int n = 4;
int &r = n; //r引用了n,r的类型是int &
r = 4;
cout << r;//输出4
cout << n;//输出4
n = 5;
cout << r;//输出5
定义引用时一定要将其初始化成引用某个变量。
初始化后,它就一直引用该变量,不会再引用别的变量了。
引用只能引用变量,不能引用常量和表达式。
double a = 4, b = 5;
double & r1 = a;
double & r2 = r1; //r2也引用a
r2 = 10;
cout << a << endl;//输出10
r1 = b;
//注意!这个语句不是让r1重新去引用b的,引用对象确定后不会更改
//这个语句实际等同于 r1 = 5
cout << a << endl;//输出5
void swap(int a, int b)
{
int tmp;
tmp = a; a = b; b = tmp;
}
int n1, n2;
swap(n1, n2);//n1, n2的值不会被交换
//因为a b是形参而不是实参,形参不会影响实参
void swap(int *a, int *b)
{
int tmp;
tmp = *a; *a = *b; *b = tmp;
//指针指向的值进行交换
}
int n1, n2;
swap(&n1, &n2);//取地址,n1, n2的值被交换
//有了c++的引用
void swap(int &a, int &b)
{
int tmp;
tmp = a; a = b; b = tmp;
}
int n1, n2;
swap(n1, n2)//n1, n2的值被交换,这样就不需要取地址了
引用作为函数的返回值
int n = 4;//全局变量
int & SetValue(){return n;}//这个函数的返回值是一个引用,引用了n
int main()
{
//这样我们可以对这个函数的返回值进行赋值,等价于对于n赋值
SetValue() = 40;
cout << n;
return 0;
}//输出40
常引用
定义引用时,前面加const关键字,即为“常引用”。
不能通过常引用去修改引用的内容。
int n;
const int & r = n;
r = 200;//编译错
n = 300;//没问题
r的类型是const int &
常引用和非常引用的转换
const T & 和 T & 是不同的类型!!!
T & 类型的引用或者T类型的变量可以用来初始化const T & 类型的引用
const T 类型的常变量和const T & 类型的引用则不能用来初始化T & 类型的引用,除非进行强制类型转换
cost关键字和常量
不可以通过常量指针去修改其指向的内容
int n, m;
const int *p = &n;
*p = 5;//编译出错
n = 4;//ok
p =& m; //ok, 常量指针的指向可以发生变化
不可以把常量指针赋值给非常量指针,反之可以
const int *p1; int *p2;
p1 = p2;//ok
p2 = p1;//error
p2 = (int*)p1;//ok,强制类型转换
函数参数为常量指针时,可以避免函数内部不小心改变参数指针所指地方的内容
void MyPrintf(const char * p)
{
strcpy(p, "this");//error
//strcpy第一个参数接受的类型是char *
//而上面已经说了不能把一个常量指针赋值给非常量指针
printf("%s", p)//ok
}
本文详细介绍了C++中的位运算,包括与(&)、或(|)、异或(^)、非(~)、左移(<<)和右移(>>)操作,并提供了实例解析。此外,还讲解了引用的概念,如何定义常引用以及常引用和非常引用的转换规则。最后,讨论了const关键字在常量和常量指针中的应用。

989

被折叠的 条评论
为什么被折叠?



