数字系统(十进制、二进制、十六进制和八进制)
本节阅读量:
在日常生活中,我们使用十进制数进行计数,其中每个数字可以是0、1、2、3、4、5、6、7、8或9。十进制也称为“基数10”,因为有10个可能的数字(0到9)。在这个系统中,我们这样计数:0、1、2、3、4、5、6、7、8、9、10、11……默认情况下,C++程序中的数字假设为十进制。
1
|
int x { 12 }; // 12 默认是十进制
|
在二进制中,只有2个数字:0和1,因此它被称为“基数2”。在二进制中,我们这样计数:0,1,10,11,100,101,110,111…
十进制和二进制是数字系统的两个例子。C++中有4种主要的数字系统。按流行程度排序,它们是:十进制(以10为基数)、二进制(以2为基数),十六进制(以16为基数)和八进制(以8为基数)。
注
本节是可选的。
以后的少量课程将出现十六进制数,因此在继续之前,您至少应该对该概念有一个大致的熟悉。
八进制和十六进制
八进制是以8为基数——也就是说,唯一可用的数字是:0、1、2、3、4、5、6和7。在八进制中,我们这样计数:0,1,2,3,4,5,6,7,10,11,12,…(注意:没有8和9,所以我们从7跳到10)。
十进制 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
八进制 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
要使用八进制字面值,请在前面加上0(零):
1
2
3
4
5
6
7
8
|
#include <iostream>
int main()
{
int x{ 012 }; // 0 开头的数据在C++中代表八进制
std::cout << x << '\n';
return 0;
}
|
该程序打印:
为什么是10而不是12?因为默认情况下数字以十进制输出,12八进制 = 10十进制。
八进制几乎不被使用,我们建议您避免使用它。
十六进制是以16为基数。在十六进制中,我们这样计数:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10,11,12…
十进制 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
十六进制 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
F |
10 |
11 |
要使用十六进制字面值,请在前面加上0x。
1
2
3
4
5
6
7
8
|
#include <iostream>
int main()
{
int x{ 0xF }; // 0x 开头的数据在C++中代表十六进制
std::cout << x << '\n';
return 0;
}
|
该程序打印:
因为十六进制数字有16个不同的值,所以一个十六进制数字包含4个bit位。因此,可以使用一对十六进制数字来精确表示整个字节。
考虑值为0011 1010 0111 1111 1001 1000 0010 0110的32位整数。由于数字的长度和重复性,这不容易阅读。在十六进制中,相同的值为:3A7F 9826,这更简洁。因此,十六进制值通常用于表示内存地址或内存中的原始数据(其类型未知)。
二进制字面值
在C++14之前,不支持二进制字面值。十六进制文本为我们提供了一种有用的解决方法(您可能仍然会在现有的代码库中看到):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <iostream>
int main()
{
int bin{};
bin = 0x0001; // 将二进制 0000 0000 0000 0001 设置给变量
bin = 0x0002; // 将二进制 0000 0000 0000 0010 设置给变量
bin = 0x0004; // 将二进制 0000 0000 0000 0100 设置给变量
bin = 0x0008; // 将二进制 0000 0000 0000 1000 设置给变量
bin = 0x0010; // 将二进制 0000 0000 0001 0000 设置给变量
bin = 0x0020; // 将二进制 0000 0000 0010 0000 设置给变量
bin = 0x0040; // 将二进制 0000 0000 0100 0000 设置给变量
bin = 0x0080; // 将二进制 0000 0000 1000 0000 设置给变量
bin = 0x00FF; // 将二进制 0000 0000 1111 1111 设置给变量
bin = 0x00B3; // 将二进制 0000 0000 1011 0011 设置给变量
bin = 0xF770; // 将二进制 1111 0111 0111 0000 设置给变量
return 0;
}
|
在C++14中,可以通过使用0b前缀来使用二进制字面值:
1
2
3
4
5
6
7
8
9
10
11
12
|
#include <iostream>
int main()
{
int bin{}; // 假设是16 bit的int
bin = 0b1; // 将二进制 0000 0000 0000 0001 设置给变量
bin = 0b11; // 将二进制 0000 0000 0000 0011 设置给变量
bin = 0b1010; // 将二进制 0000 0000 0000 1010 设置给变量
bin = 0b11110000; // 将二进制 0000 0000 1111 0000 设置给变量
return 0;
}
|
数字分隔符
由于长文本可能很难读取,C++14还增加了使用引号(’)作为数字分隔符的功能。
1
2
3
4
5
6
7
8
9
|
#include <iostream>
int main()
{
int bin { 0b1011'0010 }; // 将二进制 1011 0010 设置给变量
long value { 2'132'673'462 }; // 阅读起来更加容易
return 0;
}
|
还要注意,分隔符不能出现在值的第一个数字之前:
1
|
int bin { 0b'1011'0010 }; // error: ' 在第一个数字前出现
|
数字分隔符只影响阅读体验,不会以任何方式影响对应的值。
以十进制、八进制或十六进制输出值
默认情况下,C++以十进制输出值。然而,您可以通过使用std::dec、std::oct和std::hex I/O操纵器来更改输出格式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream>
int main()
{
int x { 12 };
std::cout << x << '\n'; // 十进制 (默认)
std::cout << std::hex << x << '\n'; // 16进制
std::cout << x << '\n'; // 现在是16进制
std::cout << std::oct << x << '\n'; // 八进制
std::cout << std::dec << x << '\n'; // 重新设置回十进制
std::cout << x << '\n'; // 十进制
return 0;
}
|
这将打印:
1
2
3
4
5
6
|
12
c
c
14
12
12
|
请注意,一旦设置好之后,I/O操纵器将保持为设置的输出格式,直到再次更改。
输出二进制值
以二进制格式输出值有点困难,因为std::cout没有内置此功能。幸运的是,C++标准库包含一个名为std::bitset的类型,它将为我们完成这项工作(在头文件中)。
要使用std::bitset,我们可以定义一个std::bitset变量,并告诉std::bitset要存储多少位。位数必须是编译时常量。可以用整数值(以任何格式,包括十进制、八进制、十六进制或二进制)初始化std::bitset。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <bitset> // 引入 std::bitset
#include <iostream>
int main()
{
// std::bitset<8> 意味着要存储 8 个 bit
std::bitset<8> bin1{ 0b1100'0101 }; // 二进制的 1100 0101
std::bitset<8> bin2{ 0xC5 }; // 十六进制的 1100 0101
std::cout << bin1 << '\n' << bin2 << '\n';
std::cout << std::bitset<4>{ 0b1010 } << '\n'; // 创建一个临时的bitset并打印
return 0;
}
|
这将打印:
1
2
3
|
11000101
11000101
1010
|
在上述代码中,此行:
1
|
std::cout << std::bitset<4>{ 0b1010 } << '\n'; // 创建一个临时的bitset并打印
|
创建临时(未命名)的4位的std::bitset对象,用二进制字面值0b1010对其进行初始化,以二进制格式打印值,然后丢弃临时对象。
在C++20和C++23中,通过新的格式库(C++20)和打印库(C++23),我们有更好的选项:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <format> // C++20
#include <iostream>
#include <print> // C++23
int main()
{
std::cout << std::format("{:b}\n", 0b1010); // C++20
std::cout << std::format("{:#b}\n", 0b1010); // C++20
std::print("{:b} {:#b}\n", 0b1010, 0b1010); // C++23
return 0;
}
|
这将打印:
1
2
3
|
1010
0b1010
1010 0b1010
|