第三章 处理基本数据类型
运算符的优先级和相关性
运算符的优先级相同的话,就根据相关性计算,比如+和-优先级相同,都是左相关性,那么从左到右一次计算
优先级 | 运算符 | 相关性 |
1 | :: | 左 |
2 | () [] -> . | 左 |
后缀++ 后缀-- | ||
3 | ! ~ | 右 |
一元+ 一元- | ||
前缀++ 前缀-- | ||
寻址& 间接* | ||
C风格的强制类型转换 | ||
sizeof() | ||
new new[] delete delete[] | ||
4 | .* ->* | 左 |
5 | * / % | 左 |
6 | + - | 左 |
7 | << >> | 左 |
8 | < <= > >= | 左 |
9 | == != | 左 |
10 | & | 左 |
11 | ^ | 左 |
12 | | | 左 |
13 | && | 左 |
14 | || | 左 |
15 | ?: | 右 |
= *= /= %= += -= &= ^= |= <<= >>= | ||
throw | ||
16 | , | 左 |
位运算符
<< : 左移运算,左移n位相当于乘以2^n
>>:右移运算,右移n位相当于除以2^n
注意:计算结果最好使用static_cast显示转换成想要的类型,因为位运算默认转换成int类型
unsigned short num{ 123 };
unsigned short new_num = static_cast<unsigned short>(num << 2);
cout << num << endl; // 123 0111 1011
cout << new_num << endl; // 492 0001 1110 1100
16387左移两位,short类型最多2字节,16位,会舍弃最高两位,结果是12
unsigned short num{ 16387 };
unsigned short new_num = num << 2;
cout << num << endl; // 16387 0100 0000 0000 0011
cout << new_num << endl; // 12 0000 0000 0000 1100
也可以用移位运算符
num >>= 2; // 等价于num = static_cast<unsigned short>(num >> 2);
注意:带符号的右移,一般会在最高位填充符号位,比如负数右移运算,最高位填充1。无符号数则没有这种情况
逻辑运算
运算符 | 说明 |
~ | 按位取反,1变0,0变1 |
& | 按位与,同为1为1,否则为0 |
^ | 异或运算,相同为0,不同为1 |
| | 按位或,有一个是1为1 |
位运算的应用
方便组合和分解16位的数据
比如我们设计一个16位的数据来储存一个汽车的属性,前8位代表样式,第9位代表是否采用新能,1代表是,0代表不是,第10位代表是否采用自动挡,1代表自动挡,0表示手动挡,后6位表示汽车的大小。
那我们随意写一个
0000 1010 1100 1011
前八位0000 1010:样式10
第九位1:新能源1
第十位1:自动挡1
后六位00 1011:大小11
实际上为方便记录,四位二进制可以表示成一个十六进制数,那么上面的数可以表示为0x0acb
那么我们如何提取这四个属性呢?
首先可以根据属性的位数,设置一个mask,比如大小是后六位,那么根据按位与运算的规则,这六位设为1,其余设为0,得到一个数0000 0000 0011 1111,换算成16进制,前面8位社区,0x3f。在用这个mask和数据做按位与运算,0x0acb & 0x3f = 11。同理,可以获得是否新能源,设置new_energy_mask = 0000 0000 1000 0000, 16进制是0x80,0x0acb & 0x80 = 0x80,新能源是从左往右数第九位,右侧还有7位,所以需要右移7位,0x80 >> 7 = 1。
如果需要设置一个属性可以用按位或运算
比如自动挡是第十位,我们设置一个auto_set = 0000 0000 0100 0000,换算成十六进制0x40,直接auto_set | 数据,如果之前是非自动挡,现在设置成了自动挡
unsigned short num{ 0x0acb };
unsigned short size_mask = 0x3f;
unsigned short size = 0x00000000;
unsigned short new_energy_mask = 0x80;
unsigned short new_energy = 0x00000000;
size = num & size_mask;
new_energy = static_cast<unsigned short>(num & new_energy_mask);
new_energy = static_cast<unsigned short>(new_energy >> 7);
cout << "size=" << size <<endl; // size = 11
cout << "new_energy=" << new_energy << endl; // new_energy = 1
按8位十六进制输出流,可以使用<iomanip>标准库中的setw()和setfill();
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
unsigned int red{ 0xFF0000u};
cout << hex << setfill('0'); // hex按十六进制输出,setfill("0")空白填充为0
cout << "red=" << setw(8) << red << endl; // setw(8)按8位输出
}
枚举类型
默认枚举类型的第一个值为0,也可以显示指定
enum class Day {Mon = 1, Tue, Wed, Thr, Fri = 1, Sat, Sun};
enum class Day {Mon = 1, Tue, Wed, Thr = Wed, Fri=1, Sat, Sun};
Day today1{ Day::Mon };
Day today2{ Day::Tue };
Day today3{ Day::Wed };
Day today4{ Day::Thr };
Day today5{ Day::Fri };
Day today6{ Day::Sat };
Day today7{ Day::Sun };
cout << "today1 :" << static_cast<int>(today1) << endl; // today:1
cout << "today2 :" << static_cast<int>(today2) << endl; // today:2
cout << "today3 :" << static_cast<int>(today3) << endl; // today:3
cout << "today4 :" << static_cast<int>(today4) << endl; // today:3
cout << "today5 :" << static_cast<int>(today5) << endl; // today:1
cout << "today6 :" << static_cast<int>(today6) << endl; // today:2
cout << "today7 :" << static_cast<int>(today7) << endl; // today:3
数据类型的别名
using big = long;
变量的生存期
自动变量(局部变量):从声明开始存在,到代码块结尾(右花括号)结束。
静态变量:static关键字,在程序结束消失
分配内存的变量:在释放内存时销毁
thread_local:线程存储持续时间
全局变量
一般定义在main函数外