C语言 创建atoi函数max long long error

6tdlim6h  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(119)

我有一个问题,在输出,虽然我定义了宏的最大长长处理溢出,但它仍然给我一个错误的输出

# 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);
}

我认为问题在于这个计算结果的函数

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));
}

对于主函数,我认为逻辑是可靠的,如果有潜在的segfault,请指出

#include <stdio.h>

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

正如你所看到的,这只是函数输出之间的比较:
我的atoi:1241513983||原始:-1

ujv3wf0j

ujv3wf0j1#

if (n > LLONG_MAX && sign == 1)if (n > INT_MAX && sign == 1)更有意义,但代码仍然存在以下问题:
考虑到intlong long/unsigned long long可能是相同的宽度,因此使用(unsigned) long long并不能帮助解决int ft_atoi(const char *str)问题,因为它不能提供int的额外范围。
学究式地:INT_MAX == ULLONG_MAX可以是相同的。
在任何情况下,都不需要更宽的类型。

未阻止溢出

while (str[i] >= '0' && str[i] <= '9') n = (n * 10) + (str[i++] - '0');存在溢出和 * 未定义行为 *(UB)的风险。
相反,测试(n * 10) + (str[i++] - '0')是否可能溢出。

while (str[i] >= '0' && str[i] <= '9') {
  int digit = str[i++] - '0';
  if (n >= LLONG_MAX/10 && 
      (n > LLONG_MAX/10 || digit > LLONG_MAX%10)) {
    ; Handle overflow with TBD code
  }
  n = n*10 + digit;
}

LLONG_MIN/INT_MIN的正幅值累加失败

n * sign不能很好地返回INT_MIN,因为没有n,所以n * -1导致INT_MIN是一种可移植的定义良好的方式。
不使用较宽类型的备选项:
已测试的代码使用比int更宽的类型。

#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>

int ft_atoi(const char *str) {
  const unsigned char *ustr = (const unsigned char*) str;

  // Avoid calling is...() with negative values.  Use unsigned char * access.
  while (isspace(*ustr)) {
    ustr++;
  }

  unsigned char sign = *ustr;
  if (sign == '-' || sign == '+') {
    ustr++;
  }

  int sum = 0;
  bool empty = true;
  bool overflow = false;
  while (isdigit(*ustr)) {
    empty = false;
    int digit = *ustr++ - '0';
    if (sum <= INT_MIN / 10
        && (sum < INT_MIN / 10 || digit > -(LLONG_MIN % 10))) {
      sum = INT_MIN;
      overflow = true;
      break;
    }
    // Accumulate the negative magnitude
    sum = sum * 10 - digit;
  }

  if (empty) {
    return 0;  // Maybe set errno too?
  }

  if (sign != '-') {
    if (sum < -INT_MAX) {
      sum = INT_MAX;
      overflow = true;
    } else {
      sum = -sum;
    }
  }

  if (overflow) {
    // Maybe set errno to ERANGE?
    return sum;
  }

  // Optional
  if (*ustr != '\0') {
    ; // Maybe set errno to indicate trailing non-numeric junk?
  }

  return sum;
}
qyswt5oh

qyswt5oh2#

好的,我想我把它修好了,谢谢你的帮助,如果有人想知道这是解决办法的话。
libft. h包含:#include<limits.h>我没有定义自己的宏

#include "libft.h"

static const char   *skipwhitespace(const char *c, int *sign)
{
    while (*c == ' ' || *c == '\t' || *c == '\n'
        || *c == '\r' || *c == '\v' || *c == '\f')
        c++;
    if (*c == '-' || *c == '+')
    {
        if (*c == '-')
            *sign = -1;
        c++;
    }
    return (c);
}

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

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

我做了测试用例里面的计算,并使用指针跳过空格和符号

#include <stdio.h>

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

输出:我的回答:-1||原始:-1
如果有人想知道为什么我不使用库,我不允许使用一个函数,我没有重新创建printf只是为了测试我身边

相关问题