符合规范的编译器能否中断 uint32_t -> int16_t -> int32_t 转换?

标签 c integer-overflow

最近,我们在一些旧代码中发现了奇怪的行为。这段代码已经工作了很长时间,但在某些平台(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/

相关文章:

c - 使用 C 确保准确计时的最佳方法

C Linux - 如何从另一个程序执行程序

c - Pop in Stack 不弹出?

c++ - C++ 中高数的模幂运算

c# - C#中的算术异常

c++ - GLUPerspective 的原始 OpenGL 等价物?

c - 寻找轻量级跨平台C线程库

java - 两个数的安全平均值的解释

c - 当 int 小于 size_t 时分配给 size_t

c++ - 如何在 C++ 中将 64 位整数乘以分数同时最小化错误?