您可以通过将适当的字符串传递给 C99 nan
, nanf
,nanl
函数来控制“有效负载”位,但这些只会生成安静的 NaN,并且未指定字符串的解释(大多数实现将其视为十六进制数)。
或者,使用联合:
#ifndef __STDC_IEC_559__
#error "This program requires IEEE floating point arithmetic"
#endif
#include <stdint.h>
#include <assert.h>
static_assert(sizeof(float) == sizeof(uint32_t),
"This program requires float to be 32 bits exactly");
float nanf_with_payload_bits(uint32_t payload)
{
if (payload & 0x7FA00000) abort();
union ieee_single {
float f;
uint32_t i;
} nan;
nan.i = 0x7FA00000 | payload;
return nan.f;
}
当两种类型的大小完全相同时,写入联合的一个成员然后从另一个成员读取,不会在 C99+勘误表中引发未定义的行为。(这在 C89 中是未定义的行为,但大多数编译器将其定义为执行您期望的操作。在 C++ 中它可能仍然是未定义的行为,我不确定;但是,同样,大多数编译器将其定义为执行您期望的操作。 )
如果您使用此函数创建信令NaN,请注意它们的行为在 C99/C11 附录 F 中明确未定义。
不要试图将i
联合的组件分解为具有位域的结构。结构中位域的内存布局部分是实现定义的,部分是未指定的,特别是位域序列不一定按照与 CPU 字节序相同的顺序打包到一个字中(或者,实际上,正确打包完全)。
标准引用(所有 C99):
- 这种联合的使用只是未指定的行为:6.2.6.1p7;J.1
- 结构中位域的布局是不可预测的:6.2.6.1p1,2;6.7.2.1p10、11、13;J.3.9
- 信号 NaN 的行为未定义:F.2.1