定点转换宏,用于具有最大和最小值的16位数字:
#define SCALEFACTOR_16(N) ( 1U << N )
#define Q_MAX16 ( SCALEFACTOR_16(16-1) - 1U )
#define Q_MIN16 ( -SCALEFACTOR_16(16-1) )
将最小值设置为64位:
int64_t x = (int64_t)Q_MIN16;
给予:
x == 0x0000 0000 ffff 8000
这是一个正数,而不是我的预期。
解决方案是将1U
更改为1UL
:
#define SCALEFACTOR_16(N) ( 1UL << N )
在这种情况下,输出正常:
x == 0xffff ffff ffff 8000
为什么第一种情况没有按预期运行?投射期间会发生什么?
答案 0 :(得分:2)
您的系统具有32位(unsigned
)int
。您正在执行的所有工作都是使用32位值,并且在完成工作后进行 转换。当您从unsigned int
转换为int64_t
时,它不会改变值(它不会将unsigned
的高位解释为要扩展的符号位),因此填充为零。
答案 1 :(得分:1)
因为要将32位无符号值(0xFFFF 8000)转换为64位有符号值(0x0000 0000 FFFF 8000)。将无符号值转换为较大的类型只会在前面添加0。将带符号的值强制转换为较大的类型会将符号位添加到前面,例如:
(int64_t)(int32_t)Q_MIN16; ==> 0xffff ffff ffff 8000
答案 2 :(得分:1)
1U
整数常量的类型为unsigned int
。移位运算的重排类型是其(提升的)左操作数的类型,在这种情况下为unsigned int
。
尽管对无符号类型执行位移位是正确的方法,但是在完成移位之后,您需要转换回预期的有符号类型。否则,由于编译器看到未签名的类型,因此转换为int64_t
的操作不会对数字“符号扩展”。
请注意,由于相同的原因,-SCALEFACTOR_16
是可疑的,它实际上不执行任何操作,因为一元减号的操作数是无符号的。从无符号类型正确转换为带符号类型时,编译器将自动处理符号,因此不需要-
。
SCALEFACTOR_16
也有一个错误,您需要将宏参数包装在括号中。
解决方案:
#define SCALEFACTOR_16(N) ( 1U << (N) )
#define Q_MAX16 ( (int16_t)(SCALEFACTOR_16(16-1) - 1U) )
#define Q_MIN16 ( (int16_t)(SCALEFACTOR_16(16-1) ) )
您也可以轻松地使该宏具有类型通用性:
#define SCALEFACTOR(N) ( 1U << (N) )
#define Q_MAX(N) ( (int##N##_t)( SCALEFACTOR(N-1) - 1U ) )
#define Q_MIN(N) ( (int##N##_t)( SCALEFACTOR(N-1) ) )
完整示例:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#define SCALEFACTOR(N) ( 1U << (N) )
#define Q_MAX(N) ( (int##N##_t)( SCALEFACTOR(N-1) - 1U ) )
#define Q_MIN(N) ( (int##N##_t)( -SCALEFACTOR(N-1) ) )
int main (void)
{
int64_t x;
x = Q_MIN(16);
printf("%.16"PRIx64 " %"PRIi64 "\n", x, x);
x = Q_MIN(32);
printf("%.16"PRIx64 " %"PRIi64 "\n", x, x);
}