欢迎光临
我们一直在努力

C语言学习笔记20260718-实现任意进制字符串转十进制(my_atoi_base)

C语言学习笔记20260718-实现任意进制字符串转十进制(my_atoi_base)

1. 核心功能与算法原理

在嵌入式开发或底层数据处理中,我们经常需要将不同进制的字符串(如十六进制的寄存器地址、二进制的状态码)转换为十进制整数。标准库的 atoi() 只能处理十进制,因此需要手动实现一个支持任意进制(2-36进制)的转换函数。

本代码的核心算法是**“秦九韶算法”(又称霍纳法则)**的变种。其核心思想是:从左到右逐位扫描,每读取一位,就将当前结果乘以进制基数,再加上当前位的数值。

例如,将十六进制字符串 "1A" 转换为十进制:

  • 初始 result = 0
  • 读取 '1' (值为1):result = 0 * 16 + 1 = 1
  • 读取 'A' (值为10):result = 1 * 16 + 10 = 26
  • 最终结果为 26。
  • 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. 关键知识点总结

  • 字符与数字的转换:在 ASCII 码中,数字字符 '0'-'9' 是连续排列的,字母 'A'-'Z' 也是连续的。利用这一特性,可以通过简单的减法完成字符到数值的映射。
  • 防溢出设计:直接进行 result * base + digit 计算在数值极大时会导致 int 溢出,产生不可预知的错误。在计算前使用 (INT_MAX – digit) / base 进行预判,是编写健壮底层库函数的必备技巧。
  • 进制范围:由于使用了 0-9 和 A-Z/a-z 作为数值符号,该算法最大支持 36 进制。
  • 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;
    }

    赞(0)
    未经允许不得转载:171主机测评 » C语言学习笔记20260718-实现任意进制字符串转十进制(my_atoi_base)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址