我一直在尝试将char数组正确转换为long strtol
,检查是否存在溢出或下溢,然后对long进行int转换.一路上,我注意到很多代码看起来像这样
if ((result == LONG_MAX || result == LONG_MIN) && errno == ERANGE)
{
// Handle the error
}
Run Code Online (Sandbox Code Playgroud)
为什么你不能只说
if(errno == ERANGE)
{
// Handle the error
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,如果发生下溢或溢出,则在两种情况下都将errno设置为ERANGE.前者真的有必要吗?可以单独检查ERANGE是否有问题?
这就是我的代码现在的样子
char *endPtr;
errno = 0;
long result = strtol(str, &endPtr, 10);
if(errno == ERANGE)
{
// Handle Error
}
else if(result > INT_MAX || result < INT_MIN)
{
// Handle Error
}
else if(endPtr == str || *endPtr != '\0')
{
// Handle Error
}
num = (int)result;
return num;
Run Code Online (Sandbox Code Playgroud)
如果有前者的原因请告诉我.
第一个代码片段是完全错误的,我稍后会解释原因,但首先我们需要一些背景知识.
errno
是一个线程局部变量.当系统调用或某些库函数失败时,它将设置为非零值.系统调用成功时,它保持不变.因此它始终包含上次调用失败的错误号.
这意味着您有两个选择.errno
在每次调用之前设置为0,或使用标准惯用语errno
.这是标准习语的伪代码
if ( foo() == some_value_that_indicates_that_an_error_occurred )
then the value in errno applies to foo
else
foo succeeded and the errno must be ignored because it could be anything
Run Code Online (Sandbox Code Playgroud)
大多数程序员都会使用标准习惯用法,因为errno
在每次系统调用之前将其设置为0是烦人的,重复的,重复的,令人讨厌的,并且令人烦恼地重复.更不用说你可能忘记errno
在它真正重要的一个地方设置为0.
回到第一个代码段.这是错误的,因为没有strtol
明确表示strtol
失败的返回值.如果strtol
返回LONG_MAX
,则可能是发生错误,或者字符串实际包含该数字LONG_MAX
.无法知道strtol
呼叫是成功还是失败.这意味着标准习惯用法(这是第一个代码片段试图实现的内容)无法使用strtol
.
要strtol
正确使用,您需要errno
在调用之前将其设置为0,如下所示
errno = 0;
result = strtol( buffer, &endptr, 10 );
if ( errno == ERANGE )
{
// handle the error
// ERANGE is the only error mentioned in the C specification
}
else if ( endptr == buffer )
{
// handle the error
// the conversion failed, i.e. the input string was empty,
// or only contained whitespace, or the first non-whitespace
// character was not valid
}
Run Code Online (Sandbox Code Playgroud)
请注意,某些实现定义了其他非零值errno
.有关详细信息,请参见适用的手册页