陷阱表示
-
C中的陷阱表示是什么(有些例子可能有帮助)? 这是否适用于C ++?
float f=3.5; int *pi = (int*)&f;
- 编辑:我知道'丕'违反别名规则,它是根据C标准的UB。 至less在GCC上它不会产生错误,但会产生警告。 在这个实现(即GCC)中,假设
sizeof(int) == sizeof(float)
做f
和*pi
有相同的二进制表示/模式? 什么MSVC?
-
陷阱表示法是C99(IIRC不是C89)用来描述适合types占用空间的位模式,但如果作为该types的值使用,则会触发未定义的行为。 这个定义在6.2.6.1p5节(6.2.6的全部触手),我不会在这里引用它,因为它很长很混乱。 这种位模式存在的types被称为“具有”陷阱表示。 不需要任何types的陷阱表示,但是标准保证不会有陷阱表示的唯一types是
unsigned char
(6.2.6.1p5,6.2.6.2p1)。这个标准给出了两个陷阱表示的假设例子,这两个例子都不对应任何真正的CPU已经做了多年的任何事情,所以我不会把你和他们混淆。 陷阱表示的一个很好的例子(也是唯一可以在任何CPU上遇到硬件级别的陷阱表示的可能遇到的情况)是一个浮点types的NaN信号。 C99附录F(第2.1节)明确地将未定义的NaN信号的行为留下,即使IEC 60559详细规定了其行为。
值得一提的是,虽然指针types允许陷阱表示,但空指针不是陷阱表示。 空指针只会导致未定义的行为,如果它们被解除引用或偏移; 对他们的其他操作(最重要的是比较和副本)是明确的。 如果仅使用具有陷阱表示的types读取它们,陷阱表示会导致未定义的行为。 ( 无效但非空指针是或应该被认为是陷阱表示是一个争论的话题,CPU不会这样对待它们,但编译器可能会这样做)。
-
您显示的代码具有未定义的行为,但这是由于指针别名规则,而不是陷阱表示。 这是如何将
float
转换为具有相同表示forms的int
(假设,如您所说,sizeof(float) == sizeof(int)
)int extract_int(float f) { union { int i; float f; } u; uf = f; return ui; }
这个代码在C99中有未指定的 (不是未定义的)行为,这基本上意味着标准没有定义生成的整数值 ,但是你得到了一些有效的整数值,它不是陷阱表示,编译器也不允许优化假设你没有这样做。 (第6.2.6.1节,第7段)。我的C99副本可能包括技术文章 – 我的回忆是原始出版物中没有定义,但在技术委员会中没有指定。
未定义的行为用指针指向一个int的别名。
一般来说,在一些平台上,任何非陷阱IEEE-754浮点值都可以表示为整数,没有任何问题。 但是,如果您假定所有浮点值都具有唯一的整数表示forms, 并且碰巧强制FPU加载该值,则会有浮点值导致意外的行为。
(来自http://www.dmh2000.com/cpp/dswap.shtml的示例);
例如,在处理FP数据时,您需要在不同的字节顺序的CPU之间进行编组,您可能会考虑执行以下操作:
double swap(double)
不幸的是,如果编译器将input加载到FPU寄存器中并且是陷阱表示,那么FPU可以用相当的陷阱表示将其写回,这恰好是不同的位表示forms。
换句话说,如果你没有正确地转换(正确的意思是通过union
, memcpy
通过char *
或者其他标准的机制),有一些FP值没有相应的位表示。