非法浮动值

Tom*_* L. 5 c gcc exception

我目前正在研究嵌入式微控制器并使用自定义printf例程.工具链是AVR32架构的GCC工具链.

我有问题,第二次调用vsnprintf或类似的CPU进入异常条件.

从支持,我得到了答案:

我们找不到任何这种行为的明显原因.但是,通过逐字节写入来创建浮点溢出条件并不安全.我们无法确保由此产生的值,建议使用"FLT_MAX"进行检查.

现在我想知道:什么是"非法"浮动值?不是所有的位组合都不应该代表至少一些值吗?如果相关:sizeof(float)是4个字节.

Eri*_*hil 5

摘要

我建议你打印浮点值的位,好像它们是十六进制整数,如下面的代码所示,这样你就可以分析这些位,看看它们是否包含你试图计算的值或者是否被错误地修改了一些bug.

细节

AVR32CU技术参考手册说:"浮点硬件符合C标准,它是基于IEEE 754浮点标准的要求."后者子句是假的; C标准不是基于IEEE 754.C标准确实指定了对IEEE 754的绑定(通过名称IEC 60559)作为C实现的可选特征.我假设您使用的AVR32 CPU型号在某种程度上符合IEEE 754.

IEEE 754中没有"非法"值.有些值不代表数字,其中一些值旨在导致异常.这样的值称为NaN(对于"非数字").有安静的NaNs和信号NaNs.安静的NaN旨在静默地传递操作,产生NaN结果.例如,3 + NaN应该生产NaN.信令NaN旨在导致异常,这可能导致程序控制的更改(例如信号或程序中止).

上面引用的技术参考手册也说"没有提供信令NaN,所有NaN都是非信令(安静)."

一个好的vsnprintf例程应该接受安静的NaN值进行打印,并且应该通过生成诸如"NaN"的字符串来格式化它们.当传递信令NaN进行格式化时,我认为将其格式化或产生异常可能是合理的.

我希望您从支持中收到的消息表明您的软件创建了某种NaN,并且vsnprintf无法处理这些消息.从措辞来看,我认为他们的反应是推测性的.

如果您通过汇编字节来创建浮点值,那么如果您的软件中存在某些错误,则可能在您不打算创建NaN时创建了NaN.我建议您通过使用vsnprintf打印浮点值的字节而不是使用浮点格式说明符打印它来调试它.

如果您使用的GCC版本具有GCC的常用功能,并且unsigned int在您的实现中是32位,则可以使用以下内容将32位float值的位格式化x为十六进制值:

vsnprintf(Buffer, BufferLength, "0x%x",
    (union { float f; unsigned int u; }) {x} .u);
Run Code Online (Sandbox Code Playgroud)

第二行使用复合文字将值x放入联合并将其字节重新解释为unsigned int.(这是C中一种支持的方式来重新解释对象的字节.许多人使用指针别名,如果使用了适当的标志,它在GCC中工作,但C标准通常不支持它.另一种支持的方法是复制字节,与unsigned int u; memcpy(&u, &x, sizeof u);.)

一旦看到其中的位float,您可以从IEEE 754标准中的信息或使用在线分析器手动解释它们.(选择"十六进制"按钮输入要解释的十六进制值.)

在IEEE-754 32位二进制浮点对象中,如果出现以下情况,则该值为NaN:

  • 比特31具有任何价值.(这是符号位,与识别NaN无关.)
  • 第30至23位都是1.
  • 位22到0不全是零.

(如果位30到23都是1但位22到0全为零,则该值为无穷大.这不是非法的,但也可能导致低质量vsnprintf生成异常.)