这是我的测试代码:
errno = 0;
d = strtod("1.8011670033376514e-308", NULL);
使用此代码,我得到d == 1.8011670033376514e-308
和errno == ERANGE
。
来自strtod(3):
如果正确的值会导致溢出,则返回正负
HUGE_VAL
(HUGE_VALF
,HUGE_VALL
)(根据值的符号)和ERANGE
存储在errno
中。如果正确的值会导致下溢,则返回零,并ERANGE
存储errno
。
所以,在我看来,errno
应为零(无错误)或d
应为零(下溢)。
这是一个错误,还是我错过了什么?对于许多不同版本的eglibc和gcc,会发生这种情况。
答案 0 :(得分:9)
在§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)浮点数具有限制:
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
错误信息具有讽刺意味的错误 - 价值太小 - 但你无法拥有一切。
答案 1 :(得分:3)
代码的行为符合The Open Group's POSIX specification of strtod()
:
如果正确的值会导致下溢,则返回一个大小不大于返回类型中最小归一化正数的值,并将errno设置为[ERANGE]。
我在Linux联机帮助页中说出你所看到的是一个错误。
答案 2 :(得分:2)
如果strtod()
返回非零值(不是+/- HUGE_VAL
),则调用成功(根据您引用的手册页)。
请参阅errno.h
的手册页:
<errno.h>
头文件定义整数变量errno
,其中 由系统调用和一些库函数设置 错误表明出了什么问题。它的价值只是重要的 当呼叫的返回值表示错误(即-1
时 大多数系统调用;来自大多数图书馆功能的-1
或NULL
;的一 成功的功能可以更改errno
。
因此,如果函数的返回值实际返回表示发生错误的值,则只能检查errno
是否有错误。
可以找到errno
的更完整说明(及其与strtod()
的关系的解释)on another StackExchange。