陷阱表示

发布于 2024-11-25 06:19:26 字数 262 浏览 5 评论 0原文

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

  2. 鉴于此代码...

    浮点数 f=3.5;
    int *pi = (int*)&f;
    

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

  1. What is a "trap representation" in C (some examples might help)? Does this apply to C++?

  2. Given this code...

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

    ... and assuming that sizeof(int) == sizeof(float), do f and *pi have the same binary representation/pattern?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

潦草背影 2024-12-02 06:19:26
  1. 陷阱表示是 C99(IIRC 不是 C89)使用的一个包罗万象的术语,用于描述适合类型占用的空间的位模式,但如果用作该类型的值,则会触发未定义的行为。该定义位于第 6.2.6.1p5 节(涉及所有 6.2.6 节),我不打算在这里引用它,因为它又长又令人困惑。存在这种位模式的类型被称为“具有”陷阱表示。任何类型都不需要具有任何陷阱表示,但标准保证具有陷阱表示的唯一类型是unsigned char(6.2.6.1p5、6.2.6.2p1) )。

    该标准给出了陷阱表示的两个假设示例,这两个示例都与任何实际 CPU 多年来所做的任何事情都不相符,因此我不会让您与它们混淆。陷阱表示的一个示例(也是您可能遇到的任何 CPU 上唯一有资格作为硬件级陷阱表示的事物)是浮点类型。尽管 IEC 60559 详细规定了 NaN 的行为,但 C99 附录 F(第 2.1 节)明确未定义发信号 NaN 的行为。

    值得一提的是,虽然指针类型允许有陷阱表示,但空指针有陷阱表示。空指针仅在取消引用或偏移时才会导致未定义的行为;对它们的其他操作(最重要的是比较和复制)是明确定义的。如果您仅使用具有陷阱表示的类型读取陷阱表示,则会导致未定义的行为。 (是否无效但非空指针被视为或应该被视为陷阱表示是一个争论的主题。CPU 不会那样对待它们,但编译器可能会这样。)

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

    int extract_int(float f)
    {
        联合{ int i;浮动 f; } 你;
        uf = f;
        返回用户界面;
    }
    

    此代码在 C99 中具有未指定(不是未定义)行为,这基本上意味着标准没有定义生成什么整数值,但您确实得到 >一些有效的整数值,它不是陷阱表示,并且不允许编译器在假设您没有这样做的情况下进行优化。 (第 6.2.6.1 节,第 7 段。我的 C99 副本可能包含技术勘误 - 我的记忆是,这在原始出版物中未定义,但在 TC 中更改为未指定。)

  1. A trap representation is a catch-all term used by C99 (IIRC not by C89) to describe bit patterns that fit into the space occupied by a type, but trigger undefined behavior if used as a value of that type. The definition is in section 6.2.6.1p5 (with tentacles into all of 6.2.6) and I'm not going to quote it here because it's long and confusing. A type for which such bit patterns exist is said to "have" trap representations. No type is required to have any trap representations, but the only type that the standard guarantees will not have trap representations is unsigned char (6.2.6.1p5, 6.2.6.2p1).

    The standard gives two hypothetical examples of trap representations, neither of which correspond to anything that any real CPU has done for many years, so I'm not going to confuse you with them. A good example of a trap representation (also the only thing that qualifies as a hardware-level trap representation on any CPU you are likely to encounter) is a signaling NaN in a floating-point type. C99 Annex F (section 2.1) explicitly leaves the behavior of signaling NaNs undefined, even though IEC 60559 specifies their behavior in detail.

    It's worth mentioning that, while pointer types are allowed to have trap representations, null pointers are not trap representations. Null pointers only cause undefined behavior if they are dereferenced or offset; other operations on them (most importantly, comparisons and copies) are well-defined. Trap representations cause undefined behavior if you merely read them using the type that has the trap representation. (Whether invalid but non-null pointers are, or should be, considered trap representations is a subject of debate. The CPU doesn't treat them that way, but the compiler might.)

  2. The code you show has undefined behavior, but this is because of the pointer-aliasing rules, not because of trap representations. This is how to convert a float into the int with the same representation (assuming, as you say, sizeof(float) == sizeof(int))

    int extract_int(float f)
    {
        union { int i; float f; } u;
        u.f = f;
        return u.i;
    }
    

    This code has unspecified (not undefined) behavior in C99, which basically means the standard doesn't define what integer value is produced, but you do get some valid integer value, it's not a trap representation, and the compiler is not allowed to optimize on the assumption that you have not done this. (Section 6.2.6.1, para 7. My copy of C99 might include technical corrigienda — my recollection is that this was undefined in the original publication but was changed to unspecified in a TC.)

白鸥掠海 2024-12-02 06:19:26

使用指向 int 的指针为 float 别名的未定义行为。

Undefined behaviour to alias a float with a pointer-to-int.

坦然微笑 2024-12-02 06:19:26

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

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

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

double swap(double)

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

换句话说,如果没有正确转换,有些浮点值没有相应的位表示(正确的意思是通过 unionmemcpy via char * 或其他标准机制)。

In general, any non-trap IEEE-754 floating point value can be represented as an integer on some platforms without any issue. However, there are floating point values that can result in unexpected behavior if you assume that all floating point values have a unique integer representation and you happen to force the FPU to load that value.

(The example is taken from Byte Swapping Floating Point Types.)

For instance, when working with floating point data you need to marshal between CPUs with different endianness, you might think of doing the following:

double swap(double)

Unfortunately, if the compiler loads the input into an FPU register and it's a trap representation, the FPU can write it back out with an equivalent trap representation that happens to be a different bit representation.

In other words, there are some floating point values that do not have a corresponding bit representation if you don't convert correctly (by correct I mean through a union, memcpy via char * or other standard mechanism).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文