【发布时间】:2012-02-09 23:16:14
【问题描述】:
最近,我们在一些旧代码中发现了奇怪的行为。这段代码已经工作了很长时间,但在某些平台(XBox 360、PowerPC)上破坏了编译器优化。通常,我会怀疑未定义的行为。
代码大致如下:
#include <stdint.h>
uint32_t sign_extend16(uint32_t val)
{
return (int32_t)(int16_t)val;
}
它是模拟器的一部分,所以有问题的操作应该不会太奇怪。 通常,我希望这仅考虑较低的 16 位并将其符号扩展为 32 位。 显然,这是它多年来的行为。在 x86_64 上,GCC 给了我这个结果:
0000000000000000 <sign_extend16>:
0: 0f bf c7 movswl %di,%eax
3: c3 retq
但是,根据我对标准的理解,如果无法用有符号类型表示无符号的值,则未定义将无符号转换为有符号。
那么编译器是否可以假设无符号值必须在[0, 32767] 的范围内,因为任何其他值都未定义?在这种情况下,对int16_t 的强制转换和对int32_t 的另一个强制转换将无济于事。在这种情况下,编译器将代码转换为简单的移动是否合法?
【问题讨论】:
-
(int16_t)val的行为永远不会不确定。如果val可以表示为int16_t,则其行为是明确定义的,否则行为是实现定义的。 -
@Maister 您在 x86_64 上到底有什么问题?
movswl指令执行符号扩展。当您传递值 32768 时,您的结果是什么?在带有gcc的32 位/64 位系统上,返回值应为0xFFFF8000。 -
我可能还不够清楚。 x86_64 上的行为是预期的。但是,它在 xbox 360 上并没有按预期运行。
-
@Maister xbox 360上的编译器是什么,参数32768返回什么值?
-
如果您通过演员
(uint16_t)明确截断val作为第一步,它可能会有所帮助;如果这样做不行,您应该尝试使用类型双关语进行转换uint16_t->int16_t...
标签: c integer-overflow