什么是C语言中的“trap representation”(可能需要一些示例)?这是否适用于C ++?
给定以下代码...
float f=3.5;
int *pi = (int*)&f;
假设 sizeof(int) == sizeof(float)
,那么 f
和 *pi
是否具有相同的二进制表示/模式?
什么是C语言中的“trap representation”(可能需要一些示例)?这是否适用于C ++?
给定以下代码...
float f=3.5;
int *pi = (int*)&f;
假设 sizeof(int) == sizeof(float)
,那么 f
和 *pi
是否具有相同的二进制表示/模式?
陷阱表示法是C99中(我记得C89不使用这个术语)用于描述位模式的一个总称,这些位模式适合于类型所占用的空间,但如果用作该类型的值,则会触发未定义行为。该定义在第6.2.6.1p5节中(涉及到6.2.6的所有内容),我不会在此引用它,因为它很长而且令人困惑。存在这种位模式的类型被认为“具有”陷阱表示法。没有任何类型需要具有陷阱表示法,但标准保证将unsigned char
排除在具有陷阱表示法之外(6.2.6.1p5,6.2.6.2p1)。
标准给出了两个假设的陷阱表示法示例,都与实际CPU已经多年不做的事情不相符,因此我不会混淆您。一个好的陷阱表示法示例(也是您可能遇到的任何CPU上唯一符合硬件级别的陷阱表示法)是浮点类型中的信号NaN。即使IEC 60559详细规定了其行为,C99附录F(第2.1节)明确将信号NaN的行为留作未定义。
值得一提的是,虽然指针类型是允许具有陷阱表示法的,但空指针不是陷阱表示法。只有当对它们进行解引用或偏移时,空指针才会导致未定义行为;其他操作(最重要的是比较和复制)则是被定义明确的。如果仅使用具有陷阱表示法的类型读取它们,则会导致未定义行为。 (无效但非空指针是否应视为陷阱表示法是争论的主题。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 可能包含技术勘误——我的记忆是在最初的出版物中这个被视为未定义的,但在 TC 中被更改为未指定的。)
将float类型与指向int的指针进行别名处理是未定义行为。
char*
可以别名化任何类型,这仅仅是实现定义的行为。或者,如果您使用的是GCC,可以使用__attribute__((may_alias))
。 - Joey Adamsdouble swap(double)
不幸的是,如果编译器将输入加载到FPU寄存器中并且它是陷阱表示,则FPU可以将其写回等效的陷阱表示,该表示恰好是不同的位表示。union
、char *
或其他标准机制进行memcpy
)进行转换,则会有一些浮点值没有相应的位表示。