转换 int 值的问题

Problems with shifting int value

所以我尝试按照以下示例进行操作:Fixed Point Arithmetic in C Programming,但出现以下错误 left shift count >= width of type

我确实在 Whosebug 上发现其他人也有这个问题,但我不明白这个错误?

#include "contiki.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

//Define sizeof - macros
#define SHIFT_AMOUNT 16 // 2^16 = 65536
#define SHIFT_MASK ((1 << SHIFT_AMOUNT) - 1) // 65535 (all LSB set, all MSB clear)

static int price = 500 << SHIFT_AMOUNT;

void calcTest(){
  price += 10 << SHIFT_AMOUNT;
  price *= 3;
  price /= 4; // now our price is ((500 + 10) * 3) / 4 = 382.5
  printf("price integer is %d\n", price >> SHIFT_AMOUNT);
  printf ("price fraction is %d\n", price & SHIFT_MASK);
}

//Defining two processors, one for making the 'knock' and one to listen
PROCESS(data_comp, "data_comp");
AUTOSTART_PROCESSES(&data_comp);

/*---------------------------------------------------------------------------*/


PROCESS_THREAD(data_comp, ev, data)
{
  static struct etimer timer;

  PROCESS_BEGIN();  
  
  /* Setup a periodic timer that expires after 10 seconds. */
  etimer_set(&timer, CLOCK_SECOND * 10);
  
  while(1) {
    calcTest();
     /* Wait for the periodic timer to expire and then restart the timer. */
    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer));
    etimer_reset(&timer);
  }

  PROCESS_END();
}

您 link 问题中的示例是为 C 实现编写的,其中 int 是 32 位。在您使用的 C 实现中,int 类型似乎是 16 位,这对于 16 位移位来说太短了。您将需要调整代码以使用更短的班次或更宽的整数类型。

每个整数类型都有一个宽度,即用于表示它的位数,包括符号位(如果类型是有符号的)和值位,但不包括填充位。

错误信息“left shift count >= width of type”表示左移量大于或等于您要移动的整数类型的宽度。例如,如果将一个 16 位数字左移 16 位,则将整数中的所有位都移出,还剩下 none。 C 标准本质上将此视为溢出:它没有定义行为。所以编译器警告你。

由于问题中的代码与问题中的错误消息不完全匹配,我们无法确定,但一种可能是您正在为 int 类型为 16 位宽的目标进行编译,所以 16 位的 SHIFT_AMOUNT 太多了。请注意,由于符号位以及 C 标准中定义的带符号整数的移位方式,移位 int 也是有问题的。移位时通常最好使用无符号类型。

可能的补救措施包括:

  • 查看您的班次金额。将 16 用于 16 位 int 会导致有点极端的定点类型。您可能需要较小的偏移量。
  • 使用更大的整数类型,也许 long
  • 使用更宽的类型进行移位并转换回来。例如,如果 long 是 32 位,您可以将 SHIFT_MASK 定义为 ((int) ((1l << SHIFT_AMOUNT) - 1)).
  • 如果已知 SHIFT_AMOUNT 至少为 1,但不超过 16,则通过使用左操作数已经移位了一点的较短移位来避免超出类型的宽度:((2 << SHIFT_AMOUNT-1) - 1).
  • 将操作分为两个班次:((1 << SHIFT_AMOUNT/2 << SHIFT_AMOUNT-SHIFT_AMOUNT/2) - 1)

注意以上选项不处理签名问题。您需要澄清上下文以获得进一步的建议。