Arduino中不需要的符号扩展

时间:2016-11-06 14:54:12

标签: c++ c arduino bit-manipulation bit-shift

我试图在Arduino中实现逻辑右移(即避免符号扩展),并且在阅读了Arduino BitShift指南(https://www.arduino.cc/en/Reference/Bitshift)之后,它建议将无符号变量向右移,不会导致符号扩展:

  

当您将x向右移位y位(x>> y)时,x中的最高位为   a 1,行为取决于x的确切数据类型。如果x是类型   int,最高位是符号位,确定x是否为   是否消极,正如我们上面所讨论的那样。在那种情况下,标志   由于历史原因,比特被复制到较低位:

int x = -16;     // binary: 1111111111110000
int y = x >> 3;  // binary: 1111111111111110 This behavior, called sign extension, is often not the behavior you want. Instead, you may
     

希望零从左侧移入。事实证明是正确的   unsigned int表达式的shift规则是不同的,所以你可以使用   一个类型转换来压制从左边复制的那些。

在我的测试中,它没有那样工作:

Serial.print( ((uint32_t)(1<<15)) >> 15, BIN);

打印:

  

11111111111111111

这意味着,正在进行标志扩展。 我也从那里尝试了建议的例子,结果相同。

我做错了吗? 是否可以进行移位并强制操作是逻辑而不是算术?

1 个答案:

答案 0 :(得分:4)

首先,我认为您遗漏了一些关键信息:看起来您必须使用具有16位/* Write a program that asks the user * to enter the starting point and end * point of the counting range and the * increment value and displays the total * of the numbers within that range */ int start; int end; int increment; int sum = 0; int count= 0; Console.WriteLine(" Enter the start number "); start = Int32.Parse(Console.ReadLine()); Console.WriteLine(" Enter the end number "); end = Int32.Parse(Console.ReadLine()); Console.WriteLine(" Enter the increment number "); increment = Int32.Parse(Console.ReadLine()); for ( start = ; end <= start ; count = count + increment ) { Console.WriteLine(" Number is: " + count); } Console.WriteLine(" Sum is: " + sum); Console.ReadKey(); 类型的Arduino板(例如,Arduino Uno)。

这里的问题是整数提升在C和C ++中的工作原理。将16位有符号整数文字int转换为32位无符号整数文字时,将执行以下步骤:

  1. 您从16位升级到32位,因此它会首先将现有的文字扩展为32位。由于它是一个已签名的文字,因此它首先符号扩展为32位有符号值。
  2. 既然操作数与所需类型的位宽相同,编译器会将其转换为32位无符号整数类型。
  3. 我没有坐16位机器来测试它,但我可以使用此测试程序在我的64位笔记本电脑上复制相同的行为:

    1<<15

    所以你可以在这个程序中看到,它不是执行不需要的符号扩展的#include <stdio.h> #include <inttypes.h> int main(int argc, const char* argv[]) { printf("%" PRIx64 "\n", ((uint64_t)(1 << 31))); // prints ffffffff80000000 printf("%" PRIx64 "\n", ((uint64_t)(1 << 31)) >> 31); // prints 1ffffffff return 0; } 操作,而是从32位有符号整数转换为64-位无符号整数,因为强制转换实际上是这样的:

    >>int32_tint64_t

    如果你想避免额外的符号扩展,你应该以无符号文字开头(正如一些程序员在他的评论中建议的那样),或者使用相同宽度的无符号类型进行转换。其中任何一个都应该有效:

    uint64_t