C中的“陷阱表示”是什么(某些例子可能有帮助)?这适用于C ++吗?
鉴于此代码......
float f=3.5;
int *pi = (int*)&f;
...假设sizeof(int) == sizeof(float)
,f
和*pi
是否具有相同的二进制表示/模式?
答案 0 :(得分:88)
陷阱表示是C99(IIRC而不是C89)用来描述适合类型占用空间的位模式的全部术语,但如果用作该类型的值,则触发未定义的行为。定义见6.2.6.1p5(6.2.6中的所有内容都有触角),我不打算在这里引用它,因为它很长而且令人困惑。存在这种位模式的类型被称为“具有”陷阱表示。没有类型需要任何陷阱表示,但标准保证将不具有陷阱表示的唯一类型是unsigned char
(6.2.6.1p5,6.2.6.2p1)。
该标准给出了陷阱表示的两个假设示例,这两个示例都不对应任何真实CPU多年来所做的任何事情,因此我不会将您与它们混淆。陷阱表示的良好示例(也是唯一的事物,它可以作为您可能遇到的任何CPU上的硬件级陷阱表示)是一个信令NaN。浮点型。 C99附件F(第2.1节)明确地将信令NaN的行为保留为未定义,即使IEC 60559详细说明了它们的行为。
值得一提的是,虽然指针类型 允许有陷阱表示,但空指针不是陷阱表示。如果取消引用或偏移,则空指针仅导致未定义的行为;对它们的其他操作(最重要的是,比较和复制)是明确定义的。如果仅使用具有陷阱表示的类型读取它们,则陷阱表示会导致未定义的行为。 (无效但是非空指针是否应该被认为是陷阱表示是一个争论的主题.CPU不会这样对待它们,但编译器可能会这样。)
您显示的代码具有未定义的行为,但这是因为指针别名规则,而不是因为陷阱表示。这是如何将float
转换为具有相同表示的int
(假设,如您所说,sizeof(float) == sizeof(int)
)
int extract_int(float f)
{
union { int i; float f; } u;
u.f = f;
return u.i;
}
此代码在C99中具有未指定(未定义)行为,这基本上意味着标准未定义生成的整数值,但您确实获得了 >某些有效整数值,它不是陷阱表示,并且在假设您没有这样做的情况下不允许编译器进行优化。 (第6.2.6.1节,第7段。我的C99副本可能包括技术corrigienda - 我的回忆是原始出版物中 未定义,但在TC中未更改。)
答案 1 :(得分:7)
使用指向int的指针定义浮点数的未定义行为。
答案 2 :(得分:2)
通常,任何非陷阱IEEE-754浮点值都可以在某些平台上表示为整数而没有任何问题。但是,如果您假设所有浮点值具有唯一的整数表示并且您恰好强制FPU加载该值,则浮点值可能会导致意外行为值。
(取自http://www.dmh2000.com/cpp/dswap.shtml)
的例子例如,在处理FP数据时,您需要在具有不同字节序的CPU之间进行编组,您可能会考虑执行以下操作:
double swap(double)
不幸的是,如果编译器将输入加载到FPU寄存器中并且它是陷阱表示,FPU可以使用等效陷阱表示将其写回,该表示恰好是不同的位表示。
换句话说,如果您没有正确转换,有些FP值没有相应的位表示(正确的意思是通过union
,memcpy
通过{{1}或其他标准机制)。