1.什么是C中的“陷阱表示”(一些例子可能会有帮助)?这适用于C++吗?1.给定此代码...
float f=3.5; int *pi = (int*)&f;
......假设sizeof(int) == sizeof(float),f和*pi是否具有相同的二进制表示/模式?
sizeof(int) == sizeof(float)
f
*pi
kqlmhetl1#
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不会这样处理它们,但编译器可能会这样处理。)1.您显示的代码有未定义的行为,但这是因为指针别名规则,而不是因为陷阱表示。这就是如何将float转换为具有相同表示的int(假设,如您所说,sizeof(float) == sizeof(int))
unsigned char
float
int
sizeof(float) == sizeof(int)
int extract_int(float f) { union { int i; float f; } u; u.f = f; return u.i; }
这段代码在C99中有 unspecified(非未定义)行为,这基本上意味着标准没有定义 * 产生什么整数值 *,但您确实得到了 * 一些 * 有效整数值,它不是陷阱表示,并且编译器不允许在您没有这样做的假设下进行优化。(见6.2.6.1,第7段。我的C99副本可能包括技术修正-我的记忆是,这是 * 是 * 未定义的原始出版物,但改为未指定的TC。)
ibps3vxo2#
使用指向int的指针为浮点值设置别名的行为未定义。
rseugnpd3#
通常,任何非陷阱IEEE-754浮点值在某些平台上都可以表示为整数而不会出现任何问题。但是,如果您假定所有浮点值都具有唯一的整数表示形式并且您碰巧强制FPU加载了该值,则有些浮点值可能会导致意外行为。(The示例取自 * Byte Swapping Floating Point Types *。)例如,当处理浮点数据时,您需要在具有不同字节序的CPU之间封送,您可以考虑执行以下操作:double swap(double)不幸的是,如果编译器将输入加载到FPU寄存器中,并且它是陷阱表示形式,则FPU可能会将它写回一个等效的陷阱表示形式,而该表示形式恰好是不同的位表示形式。换句话说,如果转换不正确(我所说的正确是指通过union、memcpy、char *或其他标准机制),有些浮点值就没有相应的位表示。
double swap(double)
union
memcpy
char *
3条答案
按热度按时间kqlmhetl1#
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不会这样处理它们,但编译器可能会这样处理。)
1.您显示的代码有未定义的行为,但这是因为指针别名规则,而不是因为陷阱表示。这就是如何将
float
转换为具有相同表示的int
(假设,如您所说,sizeof(float) == sizeof(int)
)这段代码在C99中有 unspecified(非未定义)行为,这基本上意味着标准没有定义 * 产生什么整数值 *,但您确实得到了 * 一些 * 有效整数值,它不是陷阱表示,并且编译器不允许在您没有这样做的假设下进行优化。(见6.2.6.1,第7段。我的C99副本可能包括技术修正-我的记忆是,这是 * 是 * 未定义的原始出版物,但改为未指定的TC。)
ibps3vxo2#
使用指向int的指针为浮点值设置别名的行为未定义。
rseugnpd3#
通常,任何非陷阱IEEE-754浮点值在某些平台上都可以表示为整数而不会出现任何问题。但是,如果您假定所有浮点值都具有唯一的整数表示形式并且您碰巧强制FPU加载了该值,则有些浮点值可能会导致意外行为。
(The示例取自 * Byte Swapping Floating Point Types *。)
例如,当处理浮点数据时,您需要在具有不同字节序的CPU之间封送,您可以考虑执行以下操作:
double swap(double)
不幸的是,如果编译器将输入加载到FPU寄存器中,并且它是陷阱表示形式,则FPU可能会将它写回一个等效的陷阱表示形式,而该表示形式恰好是不同的位表示形式。
换句话说,如果转换不正确(我所说的正确是指通过
union
、memcpy
、char *
或其他标准机制),有些浮点值就没有相应的位表示。