陷阱表示

Bur*_*urt 63 c c++ gcc visual-studio-2010

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

    float f=3.5;
    int *pi = (int*)&f;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 编辑:我知道'pi'违反了别名规则,根据C标准它是UB.至少在海湾合作委员会它没有产生任何错误,但警告.在这个实现(即GCC)中,假设sizeof(int) == sizeof(float)do f*pi具有相同的二进制表示/模式?MSVC怎么样?

zwo*_*wol 95

  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. 您显示的代码具有未定义的行为,但这是因为指针别名规则,而不是因为陷阱表示.这是如何将a float转换为int具有相同的表示(假设,如你所说sizeof(float) == sizeof(int))

    int extract_int(float f)
    {
        union { int i; float f; } u;
        u.f = f;
        return u.i;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    此代码在C99中具有未指定(未定义)的行为,这基本上意味着标准不定义生成的整数值,但是您确实获得了一些有效的整数值,它不是陷阱表示,并且不允许编译器进行优化假设你还没有这样做.(6.2.6.1节,第7,我的C99的副本可能包括技术corrigienda -我的回忆是,这在原来的出版物不确定,但改为不确定的TC).

  • IA64有一个名为"Not a Thing"(NaT)的整数的陷阱表示.见http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1208.htm和http://blogs.msdn.com/b/oldnewthing/archive/2004/01/19/60162 .aspx了解更多信息. (3认同)
  • 如果您仔细阅读缺陷报告,您会发现ia64的NaT*不是*实际上是符合C99标准的陷阱表示(DR要求进行更改以使其成为一个,但AFAICT从未实际发生过).类型的C99陷阱表示必须是适合分配给该类型的可见空间的位模式; NaTs是带外的.这是NaT设计糟糕的众多方法之一; 您引用的Old New Thing博客说明了另一种方式. (3认同)
  • 事实上它是C99上的UB(见附录J),这可能是一种疏忽(其他地方的措辞似乎也暗示了这一点).在C1x中它不再是UB,并且措辞更加清晰. (2认同)
  • C99中此问题的缺陷报告/ TC:www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htmff (2认同)

Pup*_*ppy 7

使用指向int的别名浮点数的未定义行为.

  • @Burt:由于严格的别名规则,使用int对float进行别名是**未定义的行为**,并且不能假设"适用于大多数编译器".但是,`char*`可以为任何类型设置别名,这只会使它成为实现定义的行为.或者,如果您正在使用GCC,则可以使用[`__attribute __((may_alias))`](http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html). (4认同)

MSN*_*MSN 5

一般来说,任何非陷阱 IEEE-754 浮点值都可以在某些平台上表示为整数,没有任何问题。但是,如果您假设所有浮点值都具有唯一的整数表示形式并且碰巧强制FPU加载该值,则某些浮点值可能会导致意外行为。

(该示例取自字节交换浮点类型。)

例如,在处理浮点数据时,您需要在具有不同字节顺序的 CPU 之间进行封送,您可能会考虑执行以下操作:

double swap(double)

不幸的是,如果编译器将输入加载到 FPU 寄存器中并且它是陷阱表示形式,则 FPU 可以使用恰好是不同位表示形式的等效陷阱表示形式将其写回。

换句话说,如果您没有正确转换(我所说的正确是指通过unionmemcpyviachar *或其他标准机制),有些浮点值将没有相应的位表示形式。