12

这是我的测试代码:

errno = 0;
d = strtod("1.8011670033376514e-308", NULL);

使用此代码,我得到d == 1.8011670033376514e-308and errno == ERANGE

从 strtod(3) 开始:

如果正确的值会导致溢出,则返回正负HUGE_VALHUGE_VALF, HUGE_VALL)(根据值的符号),并ERANGE存储在errno. 如果正确的值会导致下溢,则返回零并ERANGE存储在errno.

因此,在我看来,要么errno应该为零(无错误),要么d应该为零(下溢)。

这是一个错误,还是我错过了什么?这发生在许多不同版本的 eglibc 和 gcc 上。

4

3 回答 3

9

在 §7.22.1.3 Thestrtod()和functions中strtof()strtold() C11 标准 (ISO/IEC 9899:2011) 说:

函数返回转换后的值(如果有)。如果无法执行转换,则返回零。如果正确的值溢出并且默认舍入生效(7.12.1),则返回加减HUGE_VAL、、HUGE_VALFHUGE_VALL(根据值的返回类型和符号),并将宏的值ERANGE存储在 errno. 如果结果下溢 (7.12.1),则函数返回一个值,其大小不大于返回类型中的最小归一化正数;是否 errno获取值ERANGE是实现定义的。

该标准还在 §5.2.4.2.2浮点类型的特性中指出 IEC 60559 (IEEE 754) 浮点数有限制:

DBL_MIN 2.2250738585072014E-308 // decimal constant

由于 1.8011670033376514e-308 小于DBL_MIN,因此您会得到一个低于正常值的数字,并且ERANGE非常合适(但可选)。

在带有 GCC 4.9.1 的 Mac OS X 10.9.4 上,以下程序:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char *end;
    errno = 0;
    double d = strtod("1.8011670033376514e-308", &end);
    if (errno != 0)
    {
        int errnum = errno;
        printf("%d: %s\n", errnum, strerror(errnum));
    }
    printf("%24.16e\n", d);
    unsigned char *p = (unsigned char *)&d;
    const char *pad = "";
    for (size_t i = 0; i < sizeof(double); i++)
    {
        printf("%s0x%.2X", pad, *p++);
        pad = " ";
    }
    putchar('\n');
    return 0;
}

产生输出:

34: Result too large
 1.8011670033376514e-308
0x01 0x00 0x00 0x00 0xA8 0xF3 0x0C 0x00

具有讽刺意味的是,错误消息是错误的——值太小——但你不能拥有一切。

于 2014-08-26T06:28:33.003 回答
3

如果strtod()返回非零值(不是 +/- HUGE_VAL),则调用成功(根据您引用的手册页)。

参考手册页errno.h

<errno.h>文件定义了整型变量errno,它是由系统调用和一些库函数在发生错误时设置的,以指示出了什么问题。仅当调用的返回值指示错误时(即,-1来自大多数系统调用;-1NULL来自大多数库函数),它的值才有意义;一个成功的函数是允许改变的errno

因此,只有当您的函数的返回值实际上返回一个指示发生错误的值时,您才能检查errno错误。

可以在另一个 StackExchange上找到更完整errno的解释(及其与 的关系的解释) 。strtod()

于 2014-08-26T06:11:38.823 回答
3

该代码的行为符合The Open Group 的 POSIX 规范strtod()

如果正确的值会导致下溢,则应返回大小不大于返回类型中最小归一化正数的值,并将 errno 设置为 [ERANGE]。

我想说你看到的是 Linux 联机帮助页中的详细错误。

于 2014-08-26T06:30:19.250 回答