为什么stdlib.h中没有strtoi函数?

82

我已经习惯使用 strtod 和其变种。

我在想为什么 <stdlib.h> 没有提供 strtoi?

为什么整数类型被排除在这个函数族之外呢?

具体地,我想问为什么没有一个带有 strtod 的安全特性的 atoi 版本?

6个回答

52

为什么stdlib.h中没有strtoi函数?

并非必需。

早期的C语言没有标准的有符号整数类型比long更宽,所有较窄的转换(如int)都可以使用strtol()来完成,就像下面所做的那样。

这些函数及其无符号对应函数现在缺失于C标准库(C17/18),这是当前标准库设计上的缺陷。


在许多系统中,longint具有相同的范围,因此不需要单独的strtoi()atoi() 可以填补将字符串转换为int的快速且简便的代码需求,但可能缺乏错误检测。 在出现错误时,atoi() 会产生未定义行为(UB)。 还没有strto_short()strto_signchar() 等函数。

很容易创建一个替代strtoi()。 存在简化方式。

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

static long str2subrange(const char *s, char **endptr, int base, 
    long min, long max) {
  long y = strtol(s, endptr, base);
  if (y > max) {
    errno = ERANGE;
    return max;
  }
  if (y < min) {
    errno = ERANGE;
    return min;
  }
  return y;
}

// OP's goal
int str2i(const char *s, char **endptr, int base) {
  #if INT_MAX == LONG_MAX && INT_MIN == LONG_MIN
    return (int) strtol(s, endptr, base);
  #else
    return (int) str2subrange(s, endptr, base, INT_MIN, INT_MAX);
  #endif
}

short str2short(const char *s, char **endptr, int base) {
  return (short) str2subrange(s, endptr, base, SHRT_MIN, SHRT_MAX);
}

signed char str2schar(const char *s, char **endptr, int base) {
  return (signed char) str2subrange(s, endptr, base, SCHAR_MIN, SCHAR_MAX);
}

#include <stdint.h>
int16_t str2int16(const char *s, char **endptr, int base) {
  return (int16_t) str2subrange(s, endptr, base, INT16_MIN, INT16_MAX);
}

[2021年编辑]

为了避免与未来的库方向发生冲突,名称已从strto...()更改为str2...()
2表示to

<string.h>头文件的声明中可能会添加以strmemwcs和小写字母开头的函数名称。C17dr § 7.31.13 1


5
不确定为什么这不是被接受的答案。你对被接受答案的评论似乎没有得到足够的关注。 - Mad Physicist
@MadPhysicist 我晚了4年,而且OP自此回答3年前就没再出现过。不过它正在慢慢上升。 - chux - Reinstate Monica
另外请注意,BSD提供了strtonum()函数,它基本上就是这样做的,尽管您无法指定基数。https://linux.die.net/man/3/strtonum - Jetski S-type
2
“strtonum” 的语义是适得其反的:它在所有错误情况下返回“0”,而在溢出时返回最小值或最大值是“strtol()”的一个特性,这使得确定问题原因变得容易。手册页面声称:“现有的替代方法,如‘atoi(3)’和‘strtol(3)’,要么不可能使用,要么难以安全使用。”对于“atoi()”来说这是正确的,但是使用“strtol()”是没有困难的。 - chqrlie
在许多系统上,long和int具有相同的范围 - 在64位Windows上,它们是相等的。在64位Linux /类Unix系统上,它们不相等。https://en.cppreference.com/w/cpp/language/types - Åsmund
@Åsmund 真的。在许多嵌入式系统中,现如今每年有数十亿个,大多数都是32位系统,具有相同大小的long, int。很多(我怀疑约20%)具有32位long和16位int - chux - Reinstate Monica

50

strtol()将一个字符串转换为整数,长整数但仍然是整数。虽然有atoi()函数,但由于缺乏从无效输入报告错误的机制,大多数情况下应该避免使用它。


11
long的范围超过int的范围时,strtol()不会设置errno,也不会在int上返回INT_MIN/MAX,只会溢出并取相反数,这可能会破坏该安全功能。 - chux - Reinstate Monica
3
@chux,不确定你想表达什么。如果传递的值超出int范围,那当然不是错误。请确认是否需要进一步翻译。 - Wiz
10
由于答案没有详细说明如何使用 strtol() 来将字符串转换为 int,需要指出表示超出 int 范围(但不是 long)的字符串不会设置 errno 也不会得到限制的值。这与表示超出 long 范围的字符串的行为不同:后者会设置 errno 并获得一个有限的值。 - chux - Reinstate Monica
1
没有回答提问者的问题。 - vesperto
1
虽然有点晚,但为了完整性:在64位Linux上,long的宽度确实是64位,而int只有32位,因此范围在[2^31; 2^63)或其负数对应值[-2^63, -2^31)内的任何值都需要对int产生错误,但实际上并没有... - Aconcagua
显示剩余5条评论

3
这是我一直在使用的。
long long_val;
int  int_value;

errno = 0;
long_val = strtol (theString, NULL, 10);
if (errno)
   handle_error;
if ((long) someIntMin > long_val || long_val > (long) someIntMax)
   handle_invalid;
int_value = (int) long_val;

1
好奇,为什么要进行(long)的强制转换。看起来不必要。 - chux - Reinstate Monica

3
整数并没有被遗弃:有一个函数叫做 strtol,可以将字符串转换为 long 类型,也就是整数类型。

1
是不是只有我一个人觉得这个回答完全没有理解问题的要点?原文提问者并不是在询问"integer type",而是在询问int类型。 - xdavidliu

-5
不要忽略你的 man 页面中的 SEE ALSO 部分 :)
SEE ALSO
       atof(3), atoi(3), atol(3), strtol(3), strtoul(3)
你需要使用atoi(3)函数。 :)

3
实际上我不是。抱歉,我会澄清我的问题。 - Eli
我知道这已经很老了,但是“strto[u]l(3)”在那个“SEE ALSO”中提到了! - Tim Čas

-5

它被称为atoi。有关详细信息,包括其后继者strol,请参见Wikipedia


8
不应使用 atoi - James McNellis
3
@James McNellis atoi不应使用-- 你发表了这样的声明,好像你的理由很明显,但是由于几个答案都认为atoi()是正确的解决方案,所以它可能并不那么明显。你是否愿意向大家解释一下为什么你觉得不应该使用atoi,还是最好让它成为一个谜呢? @James McNellis认为不应该使用atoi函数,但是他没有进一步说明原因。虽然atoi可能在某些情况下是可以使用的,但是它存在一些潜在的问题:例如,如果输入的字符串无效,则会导致未定义的行为。因此,建议使用更可靠和安全的替代方法,如strtol或sscanf。 - mah
1
如果 atoi 返回 0INT_MININT_MAX,你就无法知道转换是否成功。 - James McNellis
4
@James McNellis:实际情况比这还要糟糕——规范是:“如果结果的值无法表示,则行为未定义。” - caf
4
实际上,使用 atoi 函数理论上几乎和使用 gets 函数一样糟糕:除非你对输入有非常严格的控制,否则它会导致 未定义行为。幸运的是,大多数实现并没有采取这种自由,而是在溢出时简单地产生类似于 unsigned 的包装,但你不应该依赖这一点。所以不要使用 atoi 函数。 - R.. GitHub STOP HELPING ICE
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接