定点转换16到64位?

时间:2019-11-07 14:36:12

标签: c fixed-point

定点转换宏,用于具有最大和最小值的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

为什么第一种情况没有按预期运行?投射期间会发生什么?

3 个答案:

答案 0 :(得分:2)

您的系统具有32位(unsignedint。您正在执行的所有工作都是使用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);
}