使用C语言标准库函数 (推荐)
这是最简单、最直接、也是最安全的方法,C标准库提供了 strtol() 函数,可以将一个字符串形式的数字转换为指定进制的长整型(long)值。
strtol() 函数简介
long strtol(const char *str, char **endptr, int base);
str: 指向要转换的字符串的指针。endptr: 指向一个char*类型的指针,函数执行后,*endptr会指向转换过程中停止的位置,如果字符串中包含非数字字符,转换会在第一个非数字字符处停止,如果不需要这个功能,可以传入NULL。base: 转换的基数(进制)。base是 0,函数会自动判断字符串的进制:- 如果字符串以
0x或0X开头,则被当作16进制。 - 如果字符串以
0开头,则被当作8进制(或8/10进制,取决于编译器)。 - 否则,被当作10进制。
- 如果字符串以
base是 16,则明确将字符串当作16进制处理,这通常是我们的选择。base的取值范围是 2 到 36。
示例代码
#include <stdio.h>
#include <stdlib.h> // 必须包含此头文件才能使用 strtol
#include <string.h> // 用于 strlen
int main() {
// 1. 使用字符串表示的16进制数
const char *hex_str1 = "1A3F"; // 对应的10进制是 6719
const char *hex_str2 = "0xFF"; // 对应的10进制是 255
const char *hex_str3 = "0x7FFFFFFF"; // 对应的10进制是 2147483647 (32位int的最大值)
char *endptr; // 用于存放转换结束后的位置
// 使用 strtol 进行转换,base设为16表示明确是16进制
long num1 = strtol(hex_str1, &endptr, 16);
long num2 = strtol(hex_str2, &endptr, 16);
long num3 = strtol(hex_str3, &endptr, 16);
// 打印结果
printf("字符串 \"%s\" 转换为10进制是: %ld\n", hex_str1, num1);
printf("字符串 \"%s\" 转换为10进制是: %ld\n", hex_str2, num2);
printf("字符串 \"%s\" 转换为10进制是: %ld\n", hex_str3, num3);
// 2. 处理包含非法字符的字符串
const char *hex_str4 = "1G5H"; // 'G'和'H'不是有效的16进制字符
long num4 = strtol(hex_str4, &endptr, 16);
// num4 会被成功转换到 'G' 出现之前,即 "1"
// endptr 会指向 'G'
printf("\n处理非法字符字符串 \"%s\":\n", hex_str4);
printf("成功转换的部分是: %ld\n", num4);
printf("转换停止的位置是: %c\n", *endptr); // 应该输出 'G'
return 0;
}
编译与运行:
gcc hex_to_dec.c -o hex_to_dec ./hex_to_dec
输出结果:
字符串 "1A3F" 转换为10进制是: 6719
字符串 "0xFF" 转换为10进制是: 255
字符串 "0x7FFFFFFF" 转换为10进制是: 2147483647
处理非法字符字符串 "1G5H":
成功转换的部分是: 1
转换停止的位置是: G
手动编写转换算法
为了更好地理解转换的原理,我们可以自己实现一个转换函数,16进制转10进制的核心思想是按权展开求和。
一个16进制数 dn dn-1 ... d2 d1 d0 的10进制值为:
Value = dn * 16^n + dn-1 * 16^(n-1) + ... + d2 * 16^2 + d1 * 16^1 + d0 * 16^0
1A3F 的转换过程是:
1 * 16^3 + 10 * 16^2 + 3 * 16^1 + 15 * 16^0
= 1 * 4096 + 10 * 256 + 3 * 16 + 15 * 1
= 4096 + 2560 + 48 + 15
= 6719
我们可以用一个循环来实现这个过程,每次循环将当前的结果乘以16,然后加上新的数字位。
实现步骤
- 初始化一个
result变量为0。 - 遍历16进制字符串的每一个字符。
- 对于每个字符,将其转换为对应的10进制数值('0'->0, '1'->1, ..., '9'->9, 'A'->10, 'B'->11, ..., 'F'->15, 'a'->10, 'b'->11, ..., 'f'->15)。
- 更新
result:result = result * 16 + current_digit_value。 - 循环结束后,
result就是最终的10进制值。
示例代码
#include <stdio.h>
#include <ctype.h> // 用于 isxdigit 和 toupper
// 手动实现16进制字符串转10进制长整型
long hexToDecManual(const char *hexStr) {
long result = 0;
if (hexStr == NULL) {
return 0;
}
// 跳过可能的 "0x" 前缀
if (hexStr[0] == '0' && (hexStr[1] == 'x' || hexStr[1] == 'X')) {
hexStr += 2;
}
while (*hexStr != '\0') {
char c = toupper(*hexStr); // 统一转换为大写,方便处理
int digitValue = 0;
if (c >= '0' && c <= '9') {
digitValue = c - '0';
} else if (c >= 'A' && c <= 'F') {
digitValue = 10 + (c - 'A');
} else {
// 遇到非法字符,停止转换
printf("警告: 遇到非法16进制字符 '%c',转换提前终止,\n", c);
break;
}
result = result * 16 + digitValue;
hexStr++;
}
return result;
}
int main() {
const char *hex_str1 = "1A3F";
const char *hex_str2 = "0xFF";
const char *hex_str3 = "abc";
const char *hex_str4 = "1G5H"; // 测试非法字符
long num1 = hexToDecManual(hex_str1);
long num2 = hexToDecManual(hex_str2);
long num3 = hexToDecManual(hex_str3);
long num4 = hexToDecManual(hex_str4);
printf("手动转换:\n");
printf("字符串 \"%s\" 转换为10进制是: %ld\n", hex_str1, num1);
printf("字符串 \"%s\" 转换为10进制是: %ld\n", hex_str2, num2);
printf("字符串 \"%s\" 转换为10进制是: %ld\n", hex_str3, num3);
printf("字符串 \"%s\" 转换为10进制是: %ld\n", hex_str4, num4);
return 0;
}
编译与运行:
gcc hex_to_dec_manual.c -o hex_to_dec_manual ./hex_to_dec_manual
输出结果:
手动转换:
字符串 "1A3F" 转换为10进制是: 6719
字符串 "0xFF" 转换为10进制是: 255
字符串 "abc" 转换为10进制是: 2748
警告: 遇到非法16进制字符 'G',转换提前终止。
字符串 "1G5H" 转换为10进制是: 27
注意,对于 "1G5H",我们的手动函数在遇到 'G' 时就停止了,所以结果是 "1" 的转换结果,即 1。
总结与对比
| 特性 | 方法一 (strtol) |
方法二 (手动算法) |
|---|---|---|
| 易用性 | 非常高,一行代码即可完成 | 较低,需要自己编写函数和逻辑 |
| 健壮性 | 高,能正确处理前缀 "0x",有错误检测机制 | 较低,需要自己处理前缀和错误 |
| 性能 | 通常是优化过的,性能很好 | 取决于实现,一般能满足需求 |
| 可读性 | 代码简洁,意图明确 | 需要理解算法才能看懂 |
| 适用场景 | 绝大多数情况下的首选,特别是处理用户输入或文件数据时 | 学习目的、面试考察、或者有特殊转换需求时 |
在实际开发中,强烈推荐使用方法一 strtol() 函数,它简单、可靠且是C语言标准的一部分,方法二则有助于深入理解16进制到10进制的转换原理,适合在学习和面试中展示你的编程基础。
