我在输出中遇到了问题,虽然我为max long long定义了宏来处理溢出,但它仍然给出了错误的输出

# define LLONG_MAX 9223372036854775807LL

正如您在这里看到的,max long long的宏

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

对于主函数,我认为逻辑是可靠的,如果存在潜在的段故障,请指出

#include <stdio.h>

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

如您所见,这只是函数之间的比较 输出:

我的原创:1241513983||原创:-1

推荐答案

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个可能是一样的.

在任何情况下,都不需要更广泛的类型.

Overflow not prevented

while (str[i] >= '0' && str[i] <= '9') n = (n * 10) + (str[i++] - '0');个风险溢出,undefined behavior个(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;
}

Accumulating the positive magnitude fails for 100

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

C++相关问答推荐

是否可以在C中进行D3 D12申请?

C指针算法在函数参数中的应用

将指针作为参数传递给函数

使用GOTO从多个嵌套循环C继续

Rust FFI--如何用给出返回引用的迭代器包装C风格的迭代器?

如何将常量char*复制到char数组

进程在写入管道时挂起

获取每个循环迭代结束时的当前时间

&;(str[i])和(&;str)[i]有什么区别?

在创建动态泛型数组时,通过realloc对故障进行分段

C语言中的外部关键字

-Wnonnull-Compare警告不是具有误导性吗?

使用Open62541向OPCUA服务器发送读请求时内存泄漏

S,在 struct 中创建匿名静态缓冲区的最佳方式是什么?

挥发性语义的形式化理解

函数指针作为函数参数 - 应该使用 const 吗?

将数组中的所有元素初始化为 struct 中的相同值

传递参数:C 和 C++ 中 array 与 *&array 和 &array[0] 的区别

GDB 跳过动态加载器代码

SSE 向量与 Epsilon 的比较