符合标准的编译器是否可以破坏uint32_t - > int16_t - > int32_t转换?

Mai*_*ter 9 c integer-overflow

最近,我们在一些旧代码中发现了奇怪的行为.这段代码已经工作了很长时间,但在某些平台(XBox 360,PowerPC)上打破了编译器优化最大化.通常,我怀疑未定义的行为.

代码看起来大致如下:

#include <stdint.h>
uint32_t sign_extend16(uint32_t val)
{
   return (int32_t)(int16_t)val;
}
Run Code Online (Sandbox Code Playgroud)

它是模拟器的一部分,所以有问题的操作不应该太奇怪.通常情况下,我希望这只考虑较低的16位并将其符号扩展为32位.显然,这是它多年来的行为.在x86_64上,GCC给出了这个结果:

0000000000000000 <sign_extend16>:
   0:   0f bf c7                movswl %di,%eax
   3:   c3                      retq
Run Code Online (Sandbox Code Playgroud)

但是,根据我对标准的理解,如果无法用signed类型表示unsigned的值,则无法定义将unsigned转换为signed.

那么编译器是否可以假设无符号值必须在范围内[0, 32767],因为任何其他值都是未定义的?在这种情况下,一个演员int16_t和另一个演员int32_t将无能为力.在这种情况下,编译器将代码转换为简单的移动是否合法?

oua*_*uah 9

两个整数类型之间的转换从不是未定义的行为.

但是一些整数转换是实现定义的.

在整数转换上,C表示:

(C99,6.3.1.3p3)"否则,新类型已签名且值无法在其中表示;结果是实现定义的,或者引发实现定义的信号."

什么呢gcc在这种情况下,记录在这里:

http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html

"为了转换为宽度为N的类型,将值减去模2 ^ N,使其在类型范围内;不会产生信号"