最近,我们在一些旧代码中发现了奇怪的行为。这段代码已经工作了很长时间,但在某些平台(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
将无济于事。在这种情况下,编译器将代码转换为简单的移动是否合法?
最佳答案
两个整数类型之间的转换绝不是未定义的行为。
但是一些整数转换是实现定义的。
关于整数转换,C 说:
(C99, 6.3.1.3p3) "Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised."
此处记录了 gcc
在这种情况下的作用:
http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
"For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised"
关于符合规范的编译器能否中断 uint32_t -> int16_t -> int32_t 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9220448/