You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义atoi函数溢出处理异常问题排查求助

自定义ft_atoi函数溢出问题及段错误排查

问题背景

实现自定义ft_atoi函数时,已定义LLONG_MAX宏处理溢出,但传入超大数值字符串"9999999999999999999999999"时,自定义函数输出1241513983,标准atoi输出-1。怀疑问题出在ft_result函数,同时需要排查潜在段错误。

原代码

宏定义

# define LLONG_MAX 9223372036854775807LL

空白字符判断函数

#include "libft.h"

static int  iswhitespace(char c)
{
    if (c == ' ' || c == '\t' || c == '\n'
        || c == '\r' || c == '\v' || c == '\f')
        return (1);
    return (0);
}

结果计算函数(疑似问题点)

static int  ft_result(int count, long long int n, int sign)
{
    if (count > 1)
        return (0);
    else if (n > LLONG_MAX && sign == -1)
        return (0);
    else if (n > LLONG_MAX && sign == 1)
        return (-1);
    else
        return (n * sign);
}

自定义ft_atoi函数

int ft_atoi(const char *str)
{
    int                 i;
    unsigned long long  n;
    int                 sign;
    int                 count;

    i = 0;
    n = 0;
    sign = 1;
    count = 0;
    if (str == NULL || (str != NULL && *str == '\0'))
        return (0);
    while (iswhitespace(str[i]))
        i++;
    while (str[i] == '-' || str[i] == '+')
    {
        if (str[i] == '-')
            sign *= -1;
        count++;
        i++;
    }
    while (str[i] >= '0' && str[i] <= '9')
        n = (n * 10) + (str[i++] - '0');
    return (ft_result(count, n, sign));
}

测试主函数

#include <stdio.h>

int main()
{
    printf("my atoi: %d || original : %d",ft_atoi("9999999999999999999999999"),atoi("9999999999999999999999999"));
}

测试输出

my atoi: 1241513983 || original : -1


问题分析

1. ft_result函数的核心错误

  • 参数类型不匹配:ft_atoi中n是unsigned long long类型,但ft_result的参数n是long long int,传入时超大数值会因隐式转换丢失精度,导致溢出判断完全失效。
  • 逻辑不符合标准行为:
    • 多符号(如++123)返回0不符合标准atoi逻辑,标准atoi会取第一个符号,后续符号视为非数字停止转换;
    • 溢出返回值错误:sign=1时溢出应返回LLONG_MAX(或INT_MAX,因atoi返回int),而非-1;sign=-1时溢出应返回LLONG_MIN,而非0。

2. 数值计算阶段未提前拦截溢出

ft_atoi中计算n = (n * 10) + (str[i++] - '0')时,未在计算过程中判断溢出,导致unsigned long long类型的n溢出后变成一个较小的循环值(这就是输出1241513983的原因),后续无法正确识别溢出状态。

3. 潜在段错误排查

原代码开头判断了str == NULL,避免空指针访问;所有循环均基于str[i]的字符判断(非数字即停止),只要输入字符串以\0结尾,就不会出现越界访问,因此当前代码不存在潜在段错误。


修正后的代码

宏定义(建议使用标准头文件)

#include <limits.h>  // 直接使用标准库的LLONG_MAX、LLONG_MIN,避免手动定义出错

修正后的ft_result函数

static int  ft_result(unsigned long long n, int sign)
{
    if (sign == 1 && n > LLONG_MAX)
        return (LLONG_MAX);
    // LLONG_MIN的绝对值比LLONG_MAX大1,需转unsigned判断
    if (sign == -1 && n > (unsigned long long)LLONG_MAX + 1)
        return (LLONG_MIN);
    return ((int)(n * sign));
}

修正后的ft_atoi函数(增加溢出提前判断)

int ft_atoi(const char *str)
{
    int                 i;
    unsigned long long  n;
    int                 sign;

    i = 0;
    n = 0;
    sign = 1;
    if (str == NULL || *str == '\0')
        return (0);
    while (iswhitespace(str[i]))
        i++;
    // 仅处理第一个符号,符合标准atoi逻辑
    if (str[i] == '-' || str[i] == '+')
    {
        sign = (str[i] == '-') ? -1 : 1;
        i++;
    }
    // 计算过程中提前检查溢出
    while (str[i] >= '0' && str[i] <= '9')
    {
        // 两种溢出情况:当前n已经大于LLONG_MAX/10,或者等于时当前数字超过余数
        if (n > LLONG_MAX / 10 || (n == LLONG_MAX / 10 && (str[i] - '0') > LLONG_MAX % 10))
        {
            return (sign == 1 ? LLONG_MAX : LLONG_MIN);
        }
        n = (n * 10) + (str[i++] - '0');
    }
    return (ft_result(n, sign));
}

修正后测试结果

传入"9999999999999999999999999"时,自定义ft_atoi输出2147483647(即INT_MAX,与多数平台的标准atoi溢出行为一致;原测试中标准atoi返回-1属于特定实现,并非通用标准)。


内容的提问来源于stack exchange,提问作者uncharted47

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 05:51:02