【发布时间】:2021-12-24 00:21:52
【问题描述】:
C2x(以及以前的):
当且仅当实现支持
float类型的安静 NaN 时,才会定义宏NAN。它扩展为一个 float 类型的常量表达式,表示一个安静的 NaN。
示例代码 (t0a.c)
#include <stdio.h>
#include <math.h>
#include <fenv.h>
#if _MSC_VER && ! __clang__ && ! __INTEL_COMPILER
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif
void print_fe_excepts_raised(void)
{
printf("exceptions raised ");
if (fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO");
if (fetestexcept(FE_INEXACT)) printf(" FE_INEXACT");
if (fetestexcept(FE_INVALID)) printf(" FE_INVALID");
if (fetestexcept(FE_OVERFLOW)) printf(" FE_OVERFLOW");
if (fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW");
if (fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
printf("\n");
}
int main(void)
{
float f;
feclearexcept(FE_ALL_EXCEPT);
f = NAN;
print_fe_excepts_raised();
(void)f;
return 0;
}
调用:
# msvc (version 19.29.30133 for x64)
$ cl t0a.c /std:c11 /Za /fp:strict && t0a.exe
exceptions raised FE_INEXACT FE_INVALID FE_OVERFLOW
# clang on Windows (version 13.0.0)
$ clang t0a.c -std=c11 -pedantic -Wall -Wextra -ffp-model=strict && ./a.exe
exceptions raised FE_INEXACT FE_INVALID FE_OVERFLOW
# gcc on Windows (version 11.2.0)
$ gcc t0a.c -std=c11 -pedantic -Wall -Wextra && ./a.exe
exceptions raised none
# gcc on Linux (version 11.2.0)
$ gcc t0a.c -std=c11 -pedantic -Wall -Wextra && ./a.out
exceptions raised none
# clang on Linux (version 13.0.0)
$ clang t0a.c -std=c11 -pedantic -Wall -Wextra -ffp-model=strict && ./a.out
exceptions raised none
对于 Windows 上的 msvc 和 clang:这是因为:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_math.h:94:9
#define NAN ((float)(INFINITY * 0.0F))
C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_math.h:90:9
#define INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_math.h:87:13
#define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
这里我们看到NAN“扩展为一个浮点类型的常量表达式,代表一个安静的NaN”。这意味着f = NAN 可能会导致浮点异常。但是,f = NAN 通常被视为“写入内存”。因此,人们可能会想:“写入内存怎么会引发浮点异常?”。
【问题讨论】:
-
首先,宏扩展为常量表达式这一事实不需要在编译时计算其值。如果扩展包含运算符并且上下文允许,则所涉及的操作可以在运行时进行评估。在这种情况下,可能是浮点 NaN 的计算导致引发 FP 异常,而不是结果分配的影响。
-
所以微软的头文件定义了一个 NAN 但它并不安静。你发现他们偏离标准的地方有点。让我们忽略好奇的人,专注于您的问题。嗯,你的问题到底是什么?
-
实际上,表达式产生的值很可能是一个安静的 NaN。 The whole thing seems fairly complicated.
标签: c floating-point c11 floating-point-exceptions c2x