strtod下溢,返回值!= 0

Pet*_*nen 12 c strtod

这是我的测试代码:

errno = 0;
d = strtod("1.8011670033376514e-308", NULL);
Run Code Online (Sandbox Code Playgroud)

有了这个代码,我得到d == 1.8011670033376514e-308errno == ERANGE.

来自strtod(3):

如果正确的值会导致溢出,则返回加号或减号HUGE_VAL(HUGE_VALF,HUGE_VALL)(根据值的符号),并ERANGE存储errno.如果正确的值会导致下溢,则返回零并ERANGE存储errno.

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

这是一个错误,还是我错过了什么?对于许多不同版本的eglibc和gcc,会发生这种情况.

Jon*_*ler 9

在§7.22.1.3 strtod(),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
Run Code Online (Sandbox Code Playgroud)

由于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;
}
Run Code Online (Sandbox Code Playgroud)

产生输出:

34: Result too large
 1.8011670033376514e-308
0x01 0x00 0x00 0x00 0xA8 0xF3 0x0C 0x00
Run Code Online (Sandbox Code Playgroud)

错误信息具有讽刺意味的错误 - 价值太小 - 但你不能拥有一切.