无符号整数的atoi的等价物

问题描述 投票:0回答:3

我正在执行两个涉及 atoi 的操作,我想知道如何使用无符号整数执行此操作,因为 atoi 似乎将它们转换为有符号整数,从而导致环绕整数溢出。我想使用 32 位无符号整数,但 atoi 有效地将我限制为 31 位无符号整数。

 if (multiplication_is_safe(atoi(argv[1]),atoi(argv[3])))
    {
     printf("%s * %s = %u \n", argv[1], argv[3], atoi(argv[1]) * atoi(argv[3]));
      return 0;
    }  else
c integer-overflow atoi
3个回答
36
投票

简单的答案是使用

strtoul()
代替。

更长的答案是,即使您需要的只是有符号的 32 位整数,或者对无符号的 31 位感到满意,

atoi()
函数也不适合您正在做的事情。

正如您已经注意到的,

atoi()
函数将字符串转换为整数。一个普通的有符号整数。然而,
atoi()
做的是错误处理。
atoi()
的规范所说的是“如果无法表示该值,则行为未定义。

strto*() 系列函数都清楚地指定了如何处理错误,因此在所有情况下都应该将

atoi()
替换为对
strtol()
的调用(将字符串转换为 long),在这种情况下,因为您想要处理无符号整数,您应该使用
strtoul()
(将字符串转换为无符号长整型)。

另请注意,如果您想处理更大的数字,可以使用

strtoll()
strtoull()
函数将字符串转换为 long long 或 unsigned long long。 (如果您只是想处理最大可能的整数值,而不关心中间的所有内容,则可以使用
strtoimax()
strtoumax()
,分别返回
intmax_t
uintmax_t
类型的值。)

POSIX 文档:


2
投票

根据您的平台,strtoul可能是您想要的:

strtoul()函数将字符串的起始部分转换为nptr 根据给定基数转换为 unsigned long int 值,该值必须 介于 2 到 36 之间,或者是特殊值 0。


0
投票

无符号整数的 atoi 等价物

...我如何用无符号整数做到这一点...

关键问题是如何检测超出目标范围 [0 ... INT_MAX]`的值。

考虑字符串可以转换为大于

UINT_MAX
或小于 0 的值的情况。

使用

strtoul()
是常见的第一步,但是,它会很乐意将负数
"-123"
转换为某个大的无符号值,而不会抱怨或设置
errno

如果

"-123"
是一个问题,请考虑:

相反,请根据需要使用

strtol()
,然后使用
strtoul()

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

// Return true when successful (and set *value).
// Else return false and set *value to some value.
bool string_to_unsigned(const char *s, unsigned *value) {
  char *endptr;
  errno = 0;
  int base = 10;

  long lvalue = strtol(s, &endptr, base);
  if (s == endptr) {
    // No conversion.
    *value = 0;
    return 0;
  }
  if (lvalue < 0) {
    *value = 0;
    errno = ERANGE; // String is negative.
    return false;
  }
  if (errno == ERANGE || lvalue > UINT_MAX) {
    // To large, let us try again via an unsigned conversion.
    errno = 0;
    unsigned long ulvalue = strtoul(s, &endptr, base);
    if (errno == ERANGE || ulvalue > UINT_MAX) {
      errno = ERANGE;
      *value = UINT_MAX;
      return false; // Value is too large,
    }
    *value = (unsigned) ulvalue;
  } else {
    *value = (unsigned) lvalue;
  }

  // Is trailing non-numeric text OK?
  // Maybe allow trailing white-space
  while (isspace(*(unsigned char *)endptr)) {
    endptr ++;
  }
  if (*endptr) {
    return false;  /// Trailing junk
  }

  return true;
}
© www.soinside.com 2019 - 2024. All rights reserved.