C语言学习笔记20260718-实现任意进制字符串转十进制(my_atoi_base)
1. 核心功能与算法原理
在嵌入式开发或底层数据处理中,我们经常需要将不同进制的字符串(如十六进制的寄存器地址、二进制的状态码)转换为十进制整数。标准库的 atoi() 只能处理十进制,因此需要手动实现一个支持任意进制(2-36进制)的转换函数。
本代码的核心算法是**“秦九韶算法”(又称霍纳法则)**的变种。其核心思想是:从左到右逐位扫描,每读取一位,就将当前结果乘以进制基数,再加上当前位的数值。
例如,将十六进制字符串 "1A" 转换为十进制:
2. 代码逻辑逐段解析
2.1 前置校验与变量初始化
函数首先对输入指针 str 和进制 base 进行合法性校验(只支持2-36进制)。同时定义了 result 用于累加结果,sign 用于记录正负号,i 作为字符串索引。
2.2 预处理:跳过空格、处理符号与十六进制前缀
- 跳过空格:使用 isspace() 循环跳过字符串开头的空白字符。
- 处理符号:检测首字符是否为 '-' 或 '+',记录符号位并移动索引。
- 处理十六进制前缀:如果进制是16,且字符串以 "0x" 或 "0X" 开头,自动跳过这两个字符,从真正的数值位开始解析。
2.3 核心转换循环
使用 while(str[i]) 逐位遍历字符串:
- 字符转数值:
- '0'-'9':直接减去 '0' 得到 0-9。
- 'A'-'Z' 或 'a'-'z':减去 'A' 或 'a' 后加 10,得到 10-35。
- 合法性判断:如果转换出的 digit 大于等于当前进制 base(例如二进制中出现了 '2'),则视为非法字符,直接跳出循环。
- 溢出检测:在累加前,通过数学公式预判 result * base + digit 是否会导致 int 溢出。如果正数溢出返回 INT_MAX,负数溢出返回 INT_MIN。
- 累加计算:执行 result = result * base + digit。
3. 关键知识点总结
4. 完整代码(Doxygen 注释版)
/**
* @file my_atoi_base.c
* @brief 自定义任意进制字符串转十进制整数工具函数
*
* 实现了支持 2-36 进制的字符串转整数功能,包含溢出检测与非法字符过滤。
* 适用于嵌入式开发、底层数据处理等场景。
*
* @author YourName
* @date 2026-07-18
* @version v1.0
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
/**
* @brief 将指定进制的字符串转换为十进制整数
*
* 核心算法采用秦九韶算法(霍纳法则),从左到右逐位扫描并累加。
* 支持跳过前导空格、处理正负号以及十六进制前缀(0x/0X)。
* 内置整数溢出检测机制,保证数值转换的安全性。
*
* @param[in] str 待转换的字符串指针(支持包含数字、大小写字母)
* @param[in] base 目标进制基数(取值范围:2 ~ 36)
*
* @return 转换后的十进制整数
* @retval 0 输入指针为空或进制非法
* @retval INT_MAX 正数转换发生溢出时返回
* @retval INT_MIN 负数转换发生溢出时返回
*
* @note 如果字符串中包含超出当前进制范围的字符,转换将提前终止并返回已累加的结果。
* @warning 该函数仅支持 2 到 36 进制,超出此范围将直接返回 0。
*/
int my_atoi_base(const char* str, int base)
{
// 前置校验:空指针与非法进制范围
if (str == NULL) return 0;
if (base < 2 || base > 36) return 0;
int result = 0;
int sign = 1;
int i = 0;
int digit;
// 1. 预处理:跳过前导空格
while (isspace(str[i])) i++;
// 2. 预处理:处理正负符号
if (str[i] == '-')
{
sign = –1;
i++;
}
else if (str[i] == '+')
{
i++;
}
// 3. 预处理:处理十六进制前缀 (0x 或 0X)
if (base == 16 && str[i] == '0' && (str[i + 1] == 'x' || str[i + 1] == 'X'))
{
i += 2;
}
// 4. 核心转换循环
while (str[i])
{
// 将字符映射为对应的数值
if (str[i] >= '0' && str[i] <= '9')
{
digit = str[i] – '0';
}
else if (str[i] >= 'A' && str[i] <= 'Z')
{
digit = str[i] – 'A' + 10;
}
else if (str[i] >= 'a' && str[i] <= 'z')
{
digit = str[i] – 'a' + 10;
}
else
{
break; // 遇到非数字/字母字符,提前终止
}
// 校验当前数值是否超出进制范围(如二进制中出现 '2')
if (digit >= base) break;
// 溢出检测:防止 result * base + digit 超出 int 范围
if (sign == 1 && result > (INT_MAX – digit) / base)
{
return INT_MAX;
}
if (sign == –1 && –result < (INT_MIN + digit) / base)
{
return INT_MIN;
}
// 秦九韶算法累加
result = result * base + digit;
i++;
}
return result * sign;
}
/**
* @brief 主函数,用于测试 my_atoi_base 转换逻辑
* @return 0 表示程序正常退出
*/
int main()
{
// 测试用例 1:十六进制转换(带 0x 前缀)
printf("十六进制 0x1A 转十进制: %d\\n", my_atoi_base("0x1A", 16));
// 测试用例 2:二进制转换
printf("二进制 1011 转十进制: %d\\n", my_atoi_base("1011", 2));
// 测试用例 3:带负号的十进制转换
printf("十进制 -100 转十进制: %d\\n", my_atoi_base("-100", 10));
// 测试用例 4:三十六进制转换(最大支持进制)
printf("三十六进制 Z 转十进制: %d\\n", my_atoi_base("Z", 36));
// 测试用例 5:溢出测试与非法输入测试
printf("非法进制(1)测试: %d\\n", my_atoi_base("101", 1));
printf("空指针测试: %d\\n", my_atoi_base(NULL, 10));
return 0;
}




