陷阱表示

时间:2011-07-17 18:22:54

标签: c++ c visual-studio-2010 gcc

  1. C中的“陷阱表示”是什么(某些例子可能有帮助)?这适用于C ++吗?

  2. 鉴于此代码......

    float f=3.5;
    int *pi = (int*)&f;
    

    ...假设sizeof(int) == sizeof(float)f*pi是否具有相同的二进制表示/模式?

3 个答案:

答案 0 :(得分:88)

  1. 陷阱表示是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不会这样对待它们,但编译器可能会这样。)

  2. 您显示的代码具有未定义的行为,但这是因为指针别名规则,而不是因为陷阱表示。这是如何将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值没有相应的位表示(正确的意思是通过unionmemcpy通过{{1}或其他标准机制)。