这是我的测试代码:
errno = 0;
d = strtod("1.8011670033376514e-308", NULL);
Run Code Online (Sandbox Code Playgroud)
有了这个代码,我得到d == 1.8011670033376514e-308和errno == ERANGE.
来自strtod(3):
如果正确的值会导致溢出,则返回加号或减号
HUGE_VAL(HUGE_VALF,HUGE_VALL)(根据值的符号),并ERANGE存储errno.如果正确的值会导致下溢,则返回零并ERANGE存储errno.
因此,在我看来,要么errno应该为零(无错误),要么d应为零(下溢).
这是一个错误,还是我错过了什么?对于许多不同版本的eglibc和gcc,会发生这种情况.
在§7.22.1.3 的strtod(),strtof()和strtold()功能的C11标准(ISO/IEC 9899:2011)说:
函数返回转换后的值(如果有).如果无法执行转换,则返回零.如果正确的值溢出且默认舍入生效(7.12.1),则加或减
HUGE_VAL,HUGE_VALF或HUGE_VALL返回(根据值的返回类型和符号),并ERANGE存储 宏的值errno.如果结果下溢(7.12.1),则函数返回一个值,该值的大小不大于返回类型中的最小归一化正数; 是否errno获取该值ERANGE是实现定义的.
该标准还在§5.2.4.2.2中注明了IEC 60559(IEEE 754)浮点数具有限制的浮动类型的特性:
Run Code Online (Sandbox Code Playgroud)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;
}
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)
错误信息具有讽刺意味的错误 - 价值太小 - 但你不能拥有一切.