5-3 数制(十进制、二进制、十六进制和八进制)

作者注
本节内容为可选学习内容。
后续课程将涉及十六进制数,因此在继续学习前,您至少应对此概念有基本了解。

在日常生活中,我们使用十进制decimal计数,其中每个数字位可以是0、1、2、3、4、5、6、7、8或9。十进制也称为“基数为10base 10”,因为它有10个可能的数字(0到9)。在此系统中,计数方式如下:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, … C++程序中的数字默认即采用十进制表示。

int x { 12 }; // 12 is assumed to be a decimal number

二进制binary中,只有两个数字:0和1,因此称为“基数为2base 2”。在二进制中,计数方式如下:0, 1, 10, 11, 100, 101, 110, 111, … 为便于阅读,较长的二进制数常以空格分隔为4位一组(例如 1101 0100)。

十进制和二进制都是数制体系numeral systems的例子,数制体系是表示数字的符号集合(如数字)的正式名称。C++支持四种主要数制体系,按使用频率排序依次为:十进制(基数10)、二进制(基数2)、十六进制(基数16)和八进制(基数8)。

命名规则

在十进制和二进制中,数字0和1具有相同含义。两种系统都称这些数字为“零”和“一”。

那么数字10呢?10是数制中最后一位单数字之后出现的数字。在十进制中,10等于九加一,我们称之为“十”。

在二进制中,10使用相同数字,但表示1加1(相当于十进制中的2)。若将二进制10称为“十”会造成混淆,因为“十”代表九加一,而此处的10代表一加一。

因此,“十”“十一”“十二”等名称通常专用于十进制数。在非十进制数系中,我们更倾向于称这些数为“一零”“一一”“一二”等。二进制101并非“一百零一”,而是“一零一”。


八进制和十六进制数值

八进制Octal是以8为基数的计数系统——即仅使用以下数字:0、1、2、3、4、5、6、7。八进制计数方式如下:0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, …(注意:没有8和9,因此从7直接跳到10)。

Decimal 0 1 2 3 4 5 6 7 8 9 10 11
Octal 0 1 2 3 4 5 6 7 10 11 12 13

要使用八进制字面量,请在字面量前添加一个 0(零):

#include <iostream>

int main()
{
    int x{ 012 }; // 0 before the number means this is octal
    std::cout << x << '\n';
    return 0;
}

该程序输出:

image

为什么是10而不是12?因为数字默认以十进制输出,而12八进制等于10十进制。

八进制极少使用,建议避免采用。

十六进制Hexadecimal是以16为基数的计数系统。其计数方式如下:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, …

Decimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Hexadecimal 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11

您也可以使用小写字母(尽管大写字母更为常见)。

要使用十六进制字面量,请在字面量前添加前缀 0x:

#include <iostream>

int main()
{
    int x{ 0xF }; // 0x before the number means this is hexadecimal
    std::cout << x << '\n';
    return 0;
}

该程序输出:

image

您也可以使用 0X 前缀,但 0x 是惯例用法,因为它更易于阅读。


数制对照表

以下是四种数制numeral systems并列展示,以便更清晰地观察它们各自的演进过程:

Decimal 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Binary 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111
Octal 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17
Hexadecimal 1 2 3 4 5 6 7 8 9 A B C D E F
Decimal 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Binary 10000 10001 10010 10011 10100 10101 10110 10111 11000 11001 11010 11011 11100 11101 11110 11111
Octal 20 21 22 23 24 25 26 27 30 31 32 33 34 35 36 37
Hexadecimal 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F

每行都遵循相同的模式:最右侧的数字从0递增至(基数-1)。当该数字达到(基数)时,它将重置为0,而左侧的数字则递增1。若该左侧数字达到(基数),则重置为0,其左侧的数字递增1。如此循环往复……


使用十六进制表示二进制

由于十六进制数字有16种不同的值,可以说单个十六进制数字包含4位。因此,一对十六进制数字可精确表示一个完整的字节。

Hexadecimal 0 1 2 3 4 5 6 7 8 9 A B C D E F
Binary 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

考虑一个二进制值为 0011 1010 0111 1111 1001 1000 0010 0110 的 32 位整数。由于位数较长且存在重复,这种表示方式不易阅读。在十六进制中,相同值表示为 3A7F 9826,显得更为简洁。正因如此,十六进制值常被用于表示内存地址或内存中的原始数据(其类型未知)。


二进制字面量

在C++14之前,不支持二进制字面量。不过十六进制字面量提供了一个实用的替代方案(在现有代码库中仍可能见到):

#include <iostream>

int main()
{
    int bin{};    // assume 16-bit ints
    bin = 0x0001; // assign binary 0000 0000 0000 0001 to the variable
    bin = 0x0002; // assign binary 0000 0000 0000 0010 to the variable
    bin = 0x0004; // assign binary 0000 0000 0000 0100 to the variable
    bin = 0x0008; // assign binary 0000 0000 0000 1000 to the variable
    bin = 0x0010; // assign binary 0000 0000 0001 0000 to the variable
    bin = 0x0020; // assign binary 0000 0000 0010 0000 to the variable
    bin = 0x0040; // assign binary 0000 0000 0100 0000 to the variable
    bin = 0x0080; // assign binary 0000 0000 1000 0000 to the variable
    bin = 0x00FF; // assign binary 0000 0000 1111 1111 to the variable
    bin = 0x00B3; // assign binary 0000 0000 1011 0011 to the variable
    bin = 0xF770; // assign binary 1111 0111 0111 0000 to the variable

    return 0;
}

从 C++14 开始,我们可以使用 0b 前缀来表示二进制字面量:

#include <iostream>

int main()
{
    int bin{};        // assume 16-bit ints
    bin = 0b1;        // assign binary 0000 0000 0000 0001 to the variable
    bin = 0b11;       // assign binary 0000 0000 0000 0011 to the variable
    bin = 0b1010;     // assign binary 0000 0000 0000 1010 to the variable
    bin = 0b11110000; // assign binary 0000 0000 1111 0000 to the variable

    return 0;
}

数字分隔符

由于长数字字面量难以阅读,C++14还新增了使用单引号(')作为数字分隔符的功能。

#include <iostream>

int main()
{
    int bin { 0b1011'0010 };  // assign binary 1011 0010 to the variable
    long value { 2'132'673'462 }; // much easier to read than 2132673462

    return 0;
}

另请注意,分隔符不能出现在值的首个数字之前:

int bin { 0b'1011'0010 };  // error: ' used before first digit of value

数字分隔符纯粹是视觉元素,不会以任何方式影响字面值。


输出十进制、八进制或十六进制数值

默认情况下,C++以十进制形式输出数值。但可通过使用std::dec、std::oct和std::hex输入输出操作符更改输出格式:

#include <iostream>

int main()
{
    int x { 12 };
    std::cout << x << '\n'; // decimal (by default)
    std::cout << std::hex << x << '\n'; // hexadecimal
    std::cout << x << '\n'; // now hexadecimal
    std::cout << std::oct << x << '\n'; // octal
    std::cout << std::dec << x << '\n'; // return to decimal
    std::cout << x << '\n'; // decimal

    return 0;
}

这将输出:

image

请注意,一旦应用,I/O 操作符将保持设置状态,用于未来的输出,直到再次更改为止。


以二进制形式输出值

以二进制形式输出值稍显复杂,因为 std::cout 并未内置此功能。所幸 C++ 标准库中包含名为 std::bitset 的类型(位于 头文件中),可实现此功能。

使用 std::bitset 时,需定义该变量并指定存储位数。位数必须是编译时常量。std::bitset 可通过整数值初始化(支持十进制、八进制、十六进制或二进制等任意格式)。

#include <bitset> // for std::bitset
#include <iostream>

int main()
{
	// std::bitset<8> means we want to store 8 bits
	std::bitset<8> bin1{ 0b1100'0101 }; // binary literal for binary 1100 0101
	std::bitset<8> bin2{ 0xC5 }; // hexadecimal literal for binary 1100 0101

	std::cout << bin1 << '\n' << bin2 << '\n';
	std::cout << std::bitset<4>{ 0b1010 } << '\n'; // create a temporary std::bitset and print it

	return 0;
}

这将输出:

image

在上面的代码中,这一行:

std::cout << std::bitset<4>{ 0b1010 } << '\n'; // create a temporary std::bitset and print it

创建一个临时(未命名的)std::bitset对象,包含4位,用二进制字面量0b1010初始化它,打印其二进制值,然后丢弃该临时对象。

相关内容
我们在第O.1课中更详细地介绍了std::bitset——通过std::bitset实现位标志与位操作。


使用格式化/打印库高级功能输出二进制值(进阶)

在C++20和C++23中,我们通过全新的格式化库(C++20)和打印库(C++23)获得了更优的二进制输出方案:

#include <format> // C++20
#include <iostream>
#include <print> // C++23

int main()
{
    std::cout << std::format("{:b}\n", 0b1010);  // C++20, {:b} formats the argument as binary digits
    std::cout << std::format("{:#b}\n", 0b1010); // C++20, {:#b} formats the argument as 0b-prefixed binary digits

    std::println("{:b} {:#b}", 0b1010, 0b1010);  // C++23, format/print two arguments (same as above) and a newline

    return 0;
}

这将输出:

image


测验时间

问题 #1

根据上表,32 在二进制和十六进制中分别表示什么?

显示解答

Binary: 10 0000
Hex: 20
posted @ 2026-02-15 16:25  游翔  阅读(0)  评论(0)    收藏  举报