目录
前言
在计算机科学领域,进制是数据表示的基础。无论是底层的二进制电路,还是高级编程语言中的数值运算,都离不开进制的概念,本人在日常学习过程中总是对计算机进制的互相转换有点不清楚,今天借助ai以及自己学过的内容进行一个疑问的解答,帮助自己也帮助大家对各进制有什么应用场景以及它们之间相互转换的规则进行梳理
一、各进制的核心作用
1. 二进制(Binary, Base-2)
- 作用:计算机硬件的基础语言,所有数据在内存和处理器中以二进制形式存储和处理。
- 特点:
- 仅包含两个数字:0 和 1。
- 每一位称为一个比特(bit),8 位组成一个字节(Byte)。
- 应用场景:
- 底层编程(如位运算、嵌入式系统)。
- 网络协议(如 IP 地址、MAC 地址)。
2. 八进制(Octal, Base-8)
- 作用:早期用于简化二进制表示,每 3 位二进制对应 1 位八进制。
- 特点:
- 使用数字 0-7。
- 前缀为
0
(如0377
表示十进制 255)。
- 应用场景:
- Unix/Linux 系统的文件权限(如
755
表示读写执行权限)。 - 早期计算机系统(如 PDP-11)。
- Unix/Linux 系统的文件权限(如
3. 十进制(Decimal, Base-10)
- 作用:人类日常使用的进制,符合直觉的数值表示。
- 特点:
- 使用数字 0-9。
- 应用场景:
- 日常计算、财务系统。
- 高级编程语言的默认数值输入 / 输出。
4. 十六进制(Hexadecimal, Base-16)
- 作用:现代计算机中最常用的二进制简化表示,每 4 位二进制对应 1 位十六进制。
- 特点:
- 使用数字 0-9 和字母 A-F(或 a-f)表示 10-15。
- 前缀为
0x
(如0xFF
表示十进制 255)。
- 应用场景:
- 内存地址(如
0x7FFFFFFF
)。 - 颜色编码(如
#FF0000
表示红色)。 - 加密算法(如 MD5、SHA-256 哈希值)。
- 在进程等待时从status中取得终止信号和退出状态以及是否core dump
- 内存地址(如
通过status&0x7F(也就是二进制下7个比特位为1:0000 0000 0111 1111)来取得status的前7位也就是把该进程的终止是信号拿到了,通过status右移8位再&0xFF(也就是二进制下8个比特位为1:0000 0000 1111 1111)这样就取得了status次低8位,也就是退出状态,通过status右移7位,再&0x1(0000 0000 0000 0001),这样就能取得在status下第7位的是否core dump标志了
二、进制转换的数学原理
1、十进制 ↔ 二进制转换
1. 十进制 → 二进制
方法:不断除以 2,记录余数,直到商为 0,然后反向排列余数。
示例:将十进制数 25 转换为二进制
- 25 ÷ 2 = 12 余 1
- 12 ÷ 2 = 6 余 0
- 6 ÷ 2 = 3 余 0
- 3 ÷ 2 = 1 余 1
- 1 ÷ 2 = 0 余 1
- 反向排列余数:
11001
- 验证:2⁴ + 2³ + 0 + 0 + 2⁰ = 16 + 8 + 1 = 25
2. 二进制 → 十进制
方法:按位加权求和,权重为 2 的幂次(从右到左递增)。
示例:将二进制数 10110
转换为十进制
- 1×2⁴ + 0×2³ + 1×2² + 1×2¹ + 0×2⁰
- 16 + 0 + 4 + 2 + 0 = 22
2、十进制 ↔ 八进制转换
1. 十进制 → 八进制
方法:不断除以 8,记录余数,直到商为 0,然后反向排列余数。
示例:将十进制数 53 转换为八进制
- 53 ÷ 8 = 6 余 5
- 6 ÷ 8 = 0 余 6
- 反向排列余数:
65
- 验证:6×8¹ + 5×8⁰ = 48 + 5 = 53
2. 八进制 → 十进制
方法:按位加权求和,权重为 8 的幂次(从右到左递增)。
示例:将八进制数 247
转换为十进制
- 2×8² + 4×8¹ + 7×8⁰
- 128 + 32 + 7 = 167
3、十进制 ↔ 十六进制转换
1. 十进制 → 十六进制
方法:不断除以 16,记录余数(0-9 或 A-F),直到商为 0,然后反向排列余数。
示例:将十进制数 289 转换为十六进制
- 289 ÷ 16 = 18 余 1(对应十六进制 1)
- 18 ÷ 16 = 1 余 2(对应十六进制 2)
- 1 ÷ 16 = 0 余 1(对应十六进制 1)
- 反向排列余数:
121
- 验证:1×16² + 2×16¹ + 1×16⁰ = 256 + 32 + 1 = 289
2. 十六进制 → 十进制
方法:按位加权求和,权重为 16 的幂次(从右到左递增)。
示例:将十六进制数 0x3F7
转换为十进制
- 3×16² + 15×16¹ + 7×16⁰
- 768 + 240 + 7 = 1015
4、二进制 ↔ 八进制转换
1. 二进制 → 八进制
方法:从右到左每 3 位二进制分组,不足 3 位补零,每组转换为对应的八进制数字。
示例:将二进制数 1011010
转换为八进制
- 分组:
001
011
010
- 转换每组:001 → 1,011 → 3,010 → 2
- 结果:
132
- 验证:1×8² + 3×8¹ + 2×8⁰ = 64 + 24 + 2 = 90(与二进制
1011010
对应的十进制一致)
2. 八进制 → 二进制
方法:将每个八进制数字展开为对应的 3 位二进制数。
示例:将八进制数 72
转换为二进制
- 展开每位:7 →
111
,2 →010
- 结果:
111010
5、二进制 ↔ 十六进制转换
1. 二进制 → 十六进制
方法:从右到左每 4 位二进制分组,不足 4 位补零,每组转换为对应的十六进制数字。
示例:将二进制数 11010110
转换为十六进制
- 分组:
1101
0110
- 转换每组:1101 → D,0110 → 6
- 结果:
0xD6
- 验证:D×16¹ + 6×16⁰ = 13×16 + 6 = 214(与二进制
11010110
对应的十进制一致)
2. 十六进制 → 二进制
方法:将每个十六进制数字展开为对应的 4 位二进制数。
示例:将十六进制数 0x2A
转换为二进制
- 展开每位:2 →
0010
,A →1010
- 结果:
00101010
→ 简化为101010
6、快速转换技巧
-
二进制 → 八进制 / 十六进制:
- 二进制转八进制:每 3 位一组,直接映射(如
111
→ 7)。 - 二进制转十六进制:每 4 位一组,直接映射(如
1111
→ F)。
- 二进制转八进制:每 3 位一组,直接映射(如
-
八进制 / 十六进制 → 二进制:
- 八进制转二进制:每 1 位展开为 3 位(如 7 →
111
)。 - 十六进制转二进制:每 1 位展开为 4 位(如 F →
1111
)。
- 八进制转二进制:每 1 位展开为 3 位(如 7 →
-
多进制通用转换:
任何进制之间的转换都可以通过十进制作为中间桥梁进行:
A进制 → 十进制 → B进制
7、常见进制对照表
十进制 | 二进制 | 八进制 | 十六进制 |
---|---|---|---|
0 | 0000 | 0 | 0 |
1 | 0001 | 1 | 1 |
2 | 0010 | 2 | 2 |
3 | 0011 | 3 | 3 |
4 | 0100 | 4 | 4 |
5 | 0101 | 5 | 5 |
6 | 0110 | 6 | 6 |
7 | 0111 | 7 | 7 |
8 | 1000 | 10 | 8 |
9 | 1001 | 11 | 9 |
10 | 1010 | 12 | A |
11 | 1011 | 13 | B |
12 | 1100 | 14 | C |
13 | 1101 | 15 | D |
14 | 1110 | 16 | E |
15 | 1111 | 17 | F |
三、C++ 实现进制转换
以下是完整的 C++ 代码实现,包含了各进制之间的相互转换函数:
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
// ===== 十进制转换为其他进制 =====
std::string decToBin(int num)
{
if (num == 0) return "0";
std::string result;
bool isNegative = num < 0;
num = abs(num);
while (num > 0) {
result += (num % 2) ? '1' : '0';
num /= 2;
}
if (isNegative) result += '-';
std::reverse(result.begin(), result.end());
return result;
}
std::string decToOct(int num)
{
if (num == 0) return "0";
std::string result;
bool isNegative = num < 0;
num = abs(num);
while (num > 0) {
result += (num % 8) + '0';
num /= 8;
}
if (isNegative) result += '-';
std::reverse(result.begin(), result.end());
return result;
}
std::string decToHex(int num)
{
if (num == 0) return "0";
std::string result;
bool isNegative = num < 0;
num = abs(num);
const char hexChars[] = "0123456789ABCDEF";
while (num > 0) {
result += hexChars[num % 16];
num /= 16;
}
if (isNegative) result += '-';
std::reverse(result.begin(), result.end());
return result;
}
// ===== 其他进制转换为十进制 =====
int binToDec(const std::string& bin)
{
int result = 0;
bool isNegative = false;
size_t start = 0;
if (bin[0] == '-') {
isNegative = true;
start = 1;
}
for (size_t i = start; i < bin.size(); ++i) {
result = result * 2 + (bin[i] - '0');
}
return isNegative ? -result : result;
}
int octToDec(const std::string& oct)
{
int result = 0;
bool isNegative = false;
size_t start = 0;
if (oct[0] == '-') {
isNegative = true;
start = 1;
}
for (size_t i = start; i < oct.size(); ++i) {
result = result * 8 + (oct[i] - '0');
}
return isNegative ? -result : result;
}
int hexToDec(const std::string& hex)
{
int result = 0;
bool isNegative = false;
size_t start = 0;
// 跳过0x前缀
if (hex.size() >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) {
start = 2;
} else if (hex[0] == '-') {
isNegative = true;
start = 1;
}
for (size_t i = start; i < hex.size(); ++i) {
char c = toupper(hex[i]);
int val;
if (c >= '0' && c <= '9') {
val = c - '0';
} else if (c >= 'A' && c <= 'F') {
val = 10 + (c - 'A');
} else {
throw std::invalid_argument("Invalid hex character");
}
result = result * 16 + val;
}
return isNegative ? -result : result;
}
// ===== 二进制与八进制/十六进制互转 =====
std::string binToOct(const std::string& bin)
{
// 补全位数至3的倍数
std::string padded = bin;
while (padded.size() % 3 != 0) {
padded = '0' + padded;
}
std::string result;
for (size_t i = 0; i < padded.size(); i += 3) {
std::string group = padded.substr(i, 3);
int val = (group[0] - '0') * 4 + (group[1] - '0') * 2 + (group[2] - '0');
result += std::to_string(val);
}
return result;
}
std::string binToHex(const std::string& bin)
{
// 补全位数至4的倍数
std::string padded = bin;
while (padded.size() % 4 != 0) {
padded = '0' + padded;
}
std::string result;
const char hexChars[] = "0123456789ABCDEF";
for (size_t i = 0; i < padded.size(); i += 4) {
std::string group = padded.substr(i, 4);
int val = (group[0] - '0') * 8 + (group[1] - '0') * 4 +
(group[2] - '0') * 2 + (group[3] - '0');
result += hexChars[val];
}
return result;
}
std::string octToBin(const std::string& oct)
{
std::string result;
for (char c : oct) {
int val = c - '0';
std::string bin = "";
for (int i = 2; i >= 0; --i) {
bin += ((val >> i) & 1) ? '1' : '0';
}
result += bin;
}
// 移除前导零
size_t firstNonZero = result.find_first_not_of('0');
return (firstNonZero != std::string::npos) ?
result.substr(firstNonZero) : "0";
}
std::string hexToBin(const std::string& hex)
{
std::string result;
size_t start = 0;
// 跳过0x前缀
if (hex.size() >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) {
start = 2;
}
for (size_t i = start; i < hex.size(); ++i) {
char c = toupper(hex[i]);
int val;
if (c >= '0' && c <= '9') {
val = c - '0';
} else if (c >= 'A' && c <= 'F') {
val = 10 + (c - 'A');
} else {
throw std::invalid_argument("Invalid hex character");
}
std::string bin = "";
for (int i = 3; i >= 0; --i) {
bin += ((val >> i) & 1) ? '1' : '0';
}
result += bin;
}
// 移除前导零
size_t firstNonZero = result.find_first_not_of('0');
return (firstNonZero != std::string::npos) ?
result.substr(firstNonZero) : "0";
}
// ===== 主函数演示 =====
int main() {
// 测试数据
int decNum = 255;
std::string binNum = "11010110";
std::string octNum = "377";
std::string hexNum = "0xFF";
// 十进制转换
std::cout << "十进制转二进制: " << decNum << " → " << decToBin(decNum) << std::endl;
std::cout << "十进制转八进制: " << decNum << " → " << decToOct(decNum) << std::endl;
std::cout << "十进制转十六进制: " << decNum << " → " << decToHex(decNum) << std::endl;
// 其他进制转十进制
std::cout << "二进制转十进制: " << binNum << " → " << binToDec(binNum) << std::endl;
std::cout << "八进制转十进制: " << octNum << " → " << octToDec(octNum) << std::endl;
std::cout << "十六进制转十进制: " << hexNum << " → " << hexToDec(hexNum) << std::endl;
// 二进制与八进制/十六进制互转
std::cout << "二进制转八进制: " << binNum << " → " << binToOct(binNum) << std::endl;
std::cout << "二进制转十六进制: " << binNum << " → " << binToHex(binNum) << std::endl;
std::cout << "八进制转二进制: " << octNum << " → " << octToBin(octNum) << std::endl;
std::cout << "十六进制转二进制: " << hexNum << " → " << hexToBin(hexNum) << std::endl;
return 0;
}
四、代码解析与关键点
-
十进制转其他进制:
- 使用循环不断除以目标进制基数,保存余数后反向排列。
- 处理负数时,先取绝对值,最后添加符号位。
-
其他进制转十进制:
- 按位加权求和,注意处理前缀(如
0x
)和符号位。
- 按位加权求和,注意处理前缀(如
-
二进制与八进制 / 十六进制互转:
- 二进制 → 八进制 / 十六进制:按 3 位或 4 位分组,直接映射。
- 八进制 / 十六进制 → 二进制:每 1 位展开为 3 位或 4 位。
-
字符串处理:
- 使用
std::reverse
反转字符串。 - 处理前导零时,确保结果正确性(如
0
不会被移除)。
- 使用
五、应用场景与注意事项
1. 实际应用
- 嵌入式开发:直接操作二进制位(如寄存器配置)。
- 网络编程:解析 IP 地址、端口号等二进制数据。
- 密码学:处理哈希值、密钥等十六进制表示。
2. 注意事项
- 溢出问题:转换大数值时需注意数据类型范围(如
int
vslong long
)。 - 字符大小写:十六进制字符需统一处理(如
A
和a
均视为 10)。 - 前缀处理:八进制(
0
)和十六进制(0x
)的前缀需特殊处理。