c - 为什么不能只检查 errno 是否等于 ERANGE?

标签 c errno strtol

<分区>

我一直在尝试使用 strtol 将 char 数组正确转换为 long,检查是否存在上溢或下溢,然后对 long 进行 int 转换。一路上,我注意到很多代码看起来像这样

if ((result == LONG_MAX || result == LONG_MIN) && errno == ERANGE)
{
   // Handle the error
}

为什么不能直接说

if(errno == ERANGE)
{
    // Handle the error
}

据我了解,如果发生下溢或上溢,在这两种情况下,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;

如果有前者的原因,请告诉我。

最佳答案

第一个代码片段完全错误,稍后我会解释原因,但首先我们需要一些背景知识。

errnothread-local多变的。当系统调用或某些库函数失败时,它被设置为非零值。当系统调用成功时它保持不变。所以它总是包含上次失败调用的错误号。

这意味着您有两个选择。在每次调用之前将 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

大多数程序员会使用标准习惯用法,因为在每次系统调用之前将 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
}

请注意,某些实现为 errno 定义了其他非零值。有关详细信息,请参阅适用的手册页。

关于c - 为什么不能只检查 errno 是否等于 ERANGE?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36074422/

相关文章:

C open() 函数失败。难道是我的参数不对?

c - 如何使用 C 中另一个头文件中某个头文件中定义的结构?

java - C 和 Java/虚拟机代码执行

linux - Linux 中 shm_open 打印 errno 时出现段错误

c - 理解 C 中的 errno

c++ - 将 4 字节十六进制字符串转换为整数

strtol 等规范中的混淆语言

CTRL+C 没有杀死我的程序

c - 如何让 C 中的 strtol() 函数将字符串解释为二进制补码?

c++ - 抛出异常是否影响errno或设置最后一个错误码