C atoi&x2014;如何识别零和误差之间的差异?

C atoi&x2014;如何识别零和误差之间的差异?,c,atoi,C,Atoi,返回值 成功时,函数将转换后的整数作为int值返回。 如果无法执行有效转换,则返回零值。 如果正确的值超出可表示值的范围,则返回INT_MAX或INT_MIN 那么我如何区分atoi(“poop”)和atoi(“0”)和atoi(“0000000”) 是的,我可以循环检查所有的零,以防我得到0的结果,但是没有更好的方法吗 注意:我使用ANSI C89这是atoi有时被认为不安全的原因之一。改用strtol/strtoul。如果你有,就用它 函数atoi比您想象的更危险。说: 如果无法表示该值,则

返回值 成功时,函数将转换后的整数作为
int
值返回。 如果无法执行有效转换,则返回零值。 如果正确的值超出可表示值的范围,则返回INT_MAX或INT_MIN

那么我如何区分
atoi(“poop”)
atoi(“0”)
atoi(“0000000”)

是的,我可以循环检查所有的零,以防我得到0的结果,但是没有更好的方法吗


注意:我使用ANSI C89

这是
atoi
有时被认为不安全的原因之一。改用
strtol
/
strtoul
。如果你有,就用它

函数
atoi
比您想象的更危险。说:

如果无法表示该值,则行为未定义

C99标准还规定:

7.20.1

函数atof、atoi、atol和atol不必影响 整数表达式errno出现错误。如果结果的值为 无法表示,行为未定义

你不能

atoi
无法检测错误。如果结果无法表示,
atoi
调用未定义的行为。使用
strtol
而不是
atoi

安全证书编码建议使用
strtol
而不是
atoi
,内容如下:


如@cnicutar和@ouah所述,
atoi
无法区分有效的0和无效的字符串,从而使
strtol
系列成为更好的选项

但是为什么?如何?首先要了解
atoi
strtol
都只将字符串中的初始数字集转换为数值。任何尾随的非数字字符都将被忽略
strtol
可用于检查无效字符串,因为除了数值外,它还返回指向字符串数值部分末尾的指针。因此,如果此
end
指针仍然指向原始字符串的开头,则可以判断出有错误,并且没有转换字符串中的任何字符

如代码示例所示,还有一些其他微妙之处:

long lnum;
int num;
char *end;

errno = 0;

lnum = strtol(in_str, &end, 10);        //10 specifies base-10
if (end == in_str)     //if no characters were converted these pointers are equal
    fprintf(stderr, "ERROR: can't convert string to number\n");

//If sizeof(int) == sizeof(long), we have to explicitly check for overflows
if ((lnum == LONG_MAX || lnum == LONG_MIN) && errno == ERANGE)  
    fprintf(stderr, "ERROR: number out of range for LONG\n");

//Because strtol produces a long, check for overflow
if ( (lnum > INT_MAX) || (lnum < INT_MIN) )
    fprintf(stderr, "ERROR: number out of range for INT\n");

//Finally convert the result to a plain int (if that's what you want)
num = (int) lnum;
长lnum;
int-num;
字符*结束;
errno=0;
lnum=strtol(in_str,&end,10)//10指定基-10
if(end==in_str)//如果未转换任何字符,则这些指针相等
fprintf(stderr,“错误:无法将字符串转换为数字\n”);
//如果sizeof(int)=sizeof(long),我们必须显式地检查溢出
如果((lnum==LONG_MAX | | lnum==LONG_MIN)&&errno==ERANGE)
fprintf(stderr,“错误:数字超出长\n范围”);
//因为strtol会产生一个长的检查溢出
如果((lnum>INT_MAX)| |(lnum

注意:如果您确定输入字符串将在有效的int范围内,您可以消除
lnum
并直接强制转换strtol的返回值:
num=(int)strtolen(in_str,&end,10)

关于
atoi
,它根本不检测错误。不要信任该站点。当正确的值超出范围时,
atoi()
返回的值不在C89、C99和C11标准中。C++11标准说的更少(它在两个表中列出了
atoi
,仅此而已!)。来自的声明本质上是一厢情愿的想法和/或常见的实现——没有任何standard.TL的保证;DR:改用。这有很多好处,但是……如果
sizeof(int)==sizeof(long)
,您就没有检测到溢出。您应该设置
errno=0strtol()
之前,您需要测试
((lnum==LONG_MAX | | lnum==LONG_MIN)和&errno==ERANGE)以发现溢出。尽管它可以完成这项工作,
strtol()
实际上很难正确使用,甚至比您演示的还要难。@JonathanLeffler说得很好。我已经相应地更新了我的答案,谢谢。关于
if((lnum>INT_MAX)|(lnum
,对于
long
溢出的对称性,
if()
块也应该
errno=ERANGE并将
lnum
设置为
INT\u MAX
INT\u MIN
。不回答标题问题。