atol()和strtol()的区别

69

atol() 和 strtol() 的区别是什么?

根据它们的手册页,它们似乎具有相同的效果和匹配的参数:

long atol(const char *nptr);

long int strtol(const char *nptr, char **endptr, int base);

在一般情况下,当我不想使用base参数(我只有十进制数)时,我应该使用哪个函数?

8个回答

99

strtol可以提供更多的灵活性,因为它实际上可以告诉您整个字符串是否被转换为整数。而atol在无法将字符串转换为数字时(例如atol(“help”)中),返回0,这与atol(“0”)无法区分:

int main()
{
  int res_help = atol("help");
  int res_zero = atol("0");

  printf("Got from help: %d, from zero: %d\n", res_help, res_zero);
  return 0;
}

输出:

Got from help: 0, from zero: 0

strtol函数将使用它的endptr参数来指示转换失败的位置。

int main()
{
  char* end;
  int res_help = strtol("help", &end, 10);

  if (!*end)
    printf("Converted successfully\n");
  else
    printf("Conversion error, non-convertible part: %s", end);

  return 0;
}

输出:

Conversion error, non-convertible part: help
因此,对于任何严肃的编程,我强烈建议使用 strtol。虽然它的使用方法有些棘手,但这是有很好的原因的,正如我上面所解释的那样。atol 只适用于非常简单和可控的情况。

3
我相信你的例子中,条件应该是 if (!*end)。它将指向字符串的空终止符(如果全部转换),但本身不会被设置为 NULL。 - Jeff Mercado
这个逻辑是否也适用于Linux内核函数simple_strtol?我无法使用您的确切模型使if (!*end)条件评估为真。 - boltup_im_coding
4
这没有处理与数字超出范围有关的错误。为此需要检查 errno! - Shriram V
非常感谢。我尝试使用字符串“123ABC”进行atol操作,它确实给了我值为123的结果。所以你是对的,“对于任何严肃的编程,我强烈建议使用strtol”。 :) - someone_ smiley
1
请注意,POSIX 1003.1并不保证在atol()出现错误时返回0。引用:“如果该值无法表示,则行为未定义。” - patryk.beza
当字符串为空(仅包含空终止符)时,这将无法工作。除非您愿意接受它被转换为0。 - klutt

24

atol函数功能是strtol的子集,但atol不提供可用的错误处理能力。 ato...函数的最突出问题是在溢出的情况下导致未定义行为。注意:这不仅是缺乏错误信息反馈,而是未定义行为,即通常是无法恢复的失败。

这意味着atol函数(以及所有其他ato..函数)对于任何严肃的实际用途都几乎没有用处。这是一个设计错误,它的位置应该在C历史的垃圾场上。您应该使用strto...组中的函数执行转换。它们被引入,主要是为了纠正ato...组函数固有的问题。


19

根据atoi的man页面,它已被strtol取代。

IMPLEMENTATION NOTES
The atoi() and atoi_l() functions have been deprecated by strtol() and strtol_l() 
and should not be used in new code.

6
在新的代码中,我会始终使用 strtol。它具有错误处理功能,并且 endptr 参数允许您查看使用了字符串的哪个部分。
C99 标准关于 ato* 函数的规定如下:

除了错误处理行为外,它们等同于

atoi: (int)strtol(nptr,(char **)NULL, 10)
atol: strtol(nptr,(char **)NULL, 10)
atoll: strtoll(nptr, (char **)NULL, 10)


5

atol(str)相当于将字符串转换为长整型。

strtol(str, (char **)NULL, 10);

如果你想要结束指针(用于检查是否有更多的字符需要读取或者实际上是否已经读取了任何字符)或者使用除10以外的进制,那么请使用strtol。否则,atol就可以了。


2
如果我没记错的话,strtol()有个额外的好处是可以设置(可选的)endptr指向第一个不能被转换的字符。如果endptrNULL,则会被忽略。这样,如果您处理的字符串包含数字和字符的混合,您就可以继续进行处理。例如:
char buf[] = "213982 and the rest";
char *theRest;
long int num = strtol(buf, &theRest, 10);
printf("%ld\n", num);    /* 213982 */
printf("%s\n", theRest); /* " and the rest" */

1

strtol的手册给出了以下内容:

ERRORS
   EINVAL (not in C99) The given base contains an unsupported value.
   ERANGE The resulting value was out of range.
   The implementation may also set errno to EINVAL in case no conversion was performed (no digits seen, and 0 returned).

以下代码检查范围错误。(稍作修改 Eli 的代码)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
   errno = 0;
   char* end = 0;
   long res = strtol("83459299999999999K997", &end, 10);

   if(errno != 0)
   {
      printf("Conversion error, %s\n", strerror(errno));
   }
   else if (*end)
   {
      printf("Converted partially: %i, non-convertible part: %s\n", res, end);
   }
   else
   {
      printf("Converted successfully: %i\n", res);
   }

   return 0;
}

0

虽然这个问题很老,但内容并不是关于语言的一个重要组成部分。

其他答案未能强调两个重要细节: atolstrl 都会做同样的事情,但 atol 仅尝试解析 base 10 格式(符号和数字),并且不会给出错误。

  • strtol(以及所有返回整数类型的 strto_)可以在任何从 2 到 36 的基数中获取数字,而所有的 ato_ 函数(atoi、atol)只能获取基数为 10 的数字。

  • 如果无法解析,则两者都将返回零(0),但 strtol 可以给出解析结束的位置以及如果数字太大/太小则会出现错误。

附注:任何返回十进制数的 strto_ato_ 都使用基数 10,表示浮点数的数字和一些其他字符。


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