最近,我们在一些旧代码中发现了奇怪的行为。这段代码已经工作了很长时间,但在某些平台(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
不会做任何事情。在这种情况下,编译器将代码转换为简单的移动是否合法?