认识不同的进制:二进制、八进制、十进制和十六进制
中等22数字的“方言”:教你理解二进制、八进制、十进制和十六进制
你有没有想过,同一个数字在不同“语言”里写法会不一样?就像“5个苹果”用中文、英文、法文说出来,苹果还是那5个,但发音和写法不同。我们日常生活中最习惯的语言是十进制(用0~9十个数字),而计算机内部用的是二进制(只有0和1)。为了让人类和计算机更方便沟通,又出现了八进制和十六进制这两种“中间语言”。学会了它们,你就能看懂计算机世界里数字的真正模样了!
1. 四种进制,四种计数习惯
十进制(Decimal) —— 日常计数
我们数数时,0、1、2……9,数到10就进一位(满十进一)。比如你有23块零花钱,就是2个10块和3个1块。十进制是最自然的,因为人类有10根手指。
二进制(Binary) —— 计算机的母语
计算机里只有“开”和“关”两种状态,所以它用0和1两个数字,逢二进一。想象你有一个小盒子,每放2颗糖果,就往大盒子里放1颗,小盒子清空。这样,大盒子代表高位,小盒子代表低位。比如十进制的3,用二进制表示就是“11”(1个大盒子1颗,小盒子1颗,但大盒子也是2颗装?等一下,我们换个例子更清楚:
- 十进制0 → 二进制0
- 十进制1 → 二进制1
- 十进制2 → 二进制10(小盒子满2,清空,大盒子加1)
- 十进制3 → 二进制11(大盒子1,小盒子1)
- 十进制4 → 二进制100(大盒子满2再进一位)
你会发现二进制写起来很长,比如十进制的10,二进制是1010。计算机里所有数据最终都是二进制。
八进制(Octal) —— 二进制的“缩写”
八进制用07共8个数字,逢八进一。为什么会有八进制?因为3位二进制正好可以表示07(000~111),所以八进制可以把二进制“卷”成更短的写法。比如二进制101 010(每3位一组)就是八进制的52(5*8+2=42)。八进制在早期计算机中很常见,现在偶尔也会用到(比如文件权限设置)。
十六进制(Hexadecimal) —— 最常用的“简写”
十六进制用09和AF共16个数字,其中A代表10,B=11,C=12,D=13,E=14,F=15,逢十六进一。为什么用字母?因为数字不够用了嘛。十六进制的一大好处是:1位十六进制数字正好表示4位二进制。比如二进制1010就是十六进制A。所以用十六进制看二进制数据,眼睛舒服很多(比如内存地址、颜色值#FF00FF)。
2. 在C++里,怎么“说”这些进制?
C++允许你直接使用不同进制的字面量(就是直接写在代码里的数字),编译时会被转换成相同的值。
| 进制 | 写法规则 | 例子(都表示十进制42) |
|---|---|---|
| 十进制 | 直接写数字 | 42 |
| 二进制 | 以 0b 开头(C++14起支持) | 0b101010 |
| 八进制 | 以 0 开头 | 052(注意是数字0,不是字母O) |
| 十六进制 | 以 0x 或 0X 开头 | 0x2A 或 0X2a |
重点: 不管用什么进制写,数字的大小是一样的。比如 42、0b101010、052、0x2A 都代表同一个数值——就像“四十二”、“forty-two”都指同一个数。
下面的代码定义了一个变量,用不同进制写法赋值,输出结果都一样:
#include <iostream>
using namespace std;
int main() {
int num1 = 42; // 十进制42
int num2 = 0b101010; // 二进制42(C++14及以上版本)
int num3 = 052; // 八进制42
int num4 = 0x2A; // 十六进制42
cout << "十进制42 = " << num1 << endl;
cout << "二进制写法0b101010 = " << num2 << endl;
cout << "八进制写法052 = " << num3 << endl;
cout << "十六进制写法0x2A = " << num4 << endl;
return 0;
}
运行结果全是 42,因为编译器把不同进制的字面量都转换成了内存里相同的二进制数。
3. 如何用cout“看”出不同进制的样子?
默认情况下,cout 输出数字是十进制。但我们可以用 hex、oct 等操控符(manipulator)来改变显示方式。注意:dec、oct、hex 就像开关,一旦设置,会影响后面所有输出,直到你改回来。
#include <iostream>
#include <bitset> // 用于二进制输出
using namespace std;
int main() {
int score = 100; // 考试满分100分
cout << "十进制: " << score << endl; // 默认十进制
cout << "八进制: " << oct << score << endl; // 输出 144 (8进制)
cout << "十六进制: " << hex << score << endl; // 输出 64
cout << "二进制: " << bitset<8>(score) << endl; // 输出 01100100 (8位二进制,不足补0)
// 注意:之后如果还想输出十进制,要手动切换回来
cout << dec; // 重新设回十进制
cout << "又回到十进制: " << score << endl; // 输出100
return 0;
}
解释:
oct让cout把数字按八进制显示。100的八进制是144(1个64,4个8,4个1)。hex显示十六进制,100的十六进制是64(6个16,4个1)。- 二进制不能用简单的操控符直接显示,所以我们借助
bitset<8>(需要#include <bitset>),它会将整数转换成8位二进制字符串。<8>表示显示8位,如果不够在前面补0。
4. 手动转换:就像用不同单位换算
十进制转二进制 —— 短除法
把十进制数不断除以2,记录每次的余数(从下往上读)。
例如十进制13:
13 ÷ 2 = 6 余 1
6 ÷ 2 = 3 余 0
3 ÷ 2 = 1 余 1
1 ÷ 2 = 0 余 1
从下往上读余数:1101,所以13的二进制是1101。
十进制转八进制
不断除以8,取余数。13 ÷ 8 = 1 余 5,1 ÷ 8 = 0 余 1 → 八进制15。
十进制转十六进制
除以16,13 ÷ 16 = 0 余 13(即D) → 十六进制D。
反过来,任何进制转十进制:按位乘以基数(2、8、16)的幂次然后相加。比如二进制1101 = 1×2³ + 1×2² + 0×2¹ + 1×2⁰ = 8+4+0+1=13。
生活例子: 假设你攒了25颗糖果。
- 十进制:直接写25。
- 二进制:25 → 11001(16+8+0+0+1)。
- 八进制:25 → 31(3×8+1)。
- 十六进制:25 → 19(1×16+9)。
你看,不同进制只是“包装”方式不同,糖果数量没变。
5. 新手常见的“坑”
-
八进制数字里出现了8或9
比如int x = 08;编译器会报错,因为八进制只允许0~7。虽然0开头让编译器以为你在写八进制,但数字8不合法。正确的写法:07表示7,010表示8。 -
十六进制字母大小写混淆
0x1A和0x1a都可以,但不要写成0x1G(G不是0~F)。另外注意字母A~F对应10~15,不是a~f?其实大小写都可以,但建议统一大写或小写。 -
cout的进制状态忘了改回来
如果你用了cout << hex;,后面所有的整数输出都会变成十六进制,包括你不想改的。所以最好在输出不同进制前,先保存当前状态或者用完后立刻cout << dec;恢复。 -
二进制字面量0b需要C++14或更新版本
如果你的编译器比较老(比如C++11),可能不支持0b,需要用其他方法写二进制(比如用bitset输入)。一般现在主流编译器都支持。
6. 完整示例:一个数字的全家福
下面程序定义了两个常见数(考试成绩和零花钱),展示它们的四种进制表示:
#include <iostream>
#include <bitset> // 二进制输出需要
using namespace std;
int main() {
int exam_score = 95; // 考试成绩95分
int money = 50; // 零花钱50元
cout << "=== 考试成绩 95 分 ===" << endl;
cout << "十进制: " << exam_score << endl;
cout << "八进制: " << oct << exam_score << endl; // 输出137
cout << "十六进制: " << hex << exam_score << endl; // 输出5f(小写)
cout << "二进制: " << bitset<8>(exam_score) << endl; // 输出01011111
// 恢复十进制,并输出零花钱
cout << dec; // 很重要!否则后面的输出也是十六进制
cout << "=== 零花钱 50 元 ===" << endl;
cout << "十进制: " << money << endl;
cout << "八进制: " << oct << money << endl; // 输出62
cout << "十六进制: " << hex << money << endl; // 输出32
cout << "二进制: " << bitset<8>(money) << endl; // 输出00110010
return 0;
}
运行结果:
=== 考试成绩 95 分 ===
十进制: 95
八进制: 137
十六进制: 5f
二进制: 01011111
=== 零花钱 50 元 ===
十进制: 50
八进制: 62
十六进制: 32
二进制: 00110010
你可以看到,同一个数在不同进制下“长相”差别很大,但数值完全一样。
7. 学完这个,下一步可以看什么?
进制转换是计算机基础中的基础。理解了它,你就能更好地理解:
- 位运算:按位与(&)、或(|)、异或(^)、取反(~)、左移(<<)、右移(>>)等操作,都是直接对二进制位进行的,在游戏编程、加密算法中经常用到。
- 内存地址与指针:内存地址通常用十六进制显示(比如
0x7ffeefbff5a8),了解十六进制能让你看懂调试信息。 - 颜色值:网页颜色如
#FF8800其实就是十六进制表示的RGB颜色(R=FF, G=88, B=00)。 - 更多的进制转换算法:你可以试着写一个程序,输入十进制数,输出它的二进制、八进制、十六进制(自己实现短除法,不用cout的操控符)。
继续加油,你已经掌握了数字的“方言”,以后看计算机的世界会更清晰!
例题精讲
二进制数101101转换为十进制数是多少?
在C++中,使用八进制数时,数字前应加前缀0o?
以下C++代码使用std::hex将十进制255输出为十六进制,请填空:
#include <iostream>
int main() {
int a = 255;
std::cout << ___ << a << std::endl;
return 0;
}十六进制数A3F转换为二进制,以下哪个是正确的?
以下C++代码使用std::oct将十进制100输出为八进制,请填空:
#include <iostream>
int main() {
int a = 100;
std::cout << ___ << a << std::endl;
return 0;
}