【问题标题】:Unwanted sign extension in ArduinoArduino中不需要的符号扩展
【发布时间】:2016-11-06 14:54:12
【问题描述】:

我正在尝试在 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 表达式的移位规则不同,因此您可以使用 用于禁止从左侧复制的类型转换。

在我的测试中,它不是这样工作的:

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

打印:

11111111111111111

也就是说,正在进行符号扩展。 我还尝试了那里的建议示例,结果相同。

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

【问题讨论】:

  • 如果您使用无符号整数开头,则可以取消强制转换,如(1u &lt;&lt; 15) &gt;&gt; 15
  • &gt;&gt; 超过负值是实现定义的行为。
  • @Someprogrammerdude 即使我这样做了,符号扩展仍然会发生,虽然 15 不是负数...

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


【解决方案1】:

首先,我认为您遗漏了一些关键信息:看起来您必须使用 16 位 int 类型的 Arduino 板(例如,Arduino Uno)。

这里的问题是整数提升在 C 和 C++ 中是如何工作的。当您将 16 位有符号整数文字 1&lt;&lt;15 转换为 32 位无符号整数文字时,将采取以下步骤:

  1. 您正在从 16 位转换为 32 位,因此它将首先将您现有的文字扩展到 32 位。由于它是有符号文字,因此首先将其符号扩展为 32 位有符号值。
  2. 现在操作数具有与所需类型相同的位宽,编译器将其转换为 32 位无符号整数类型。

我没有 16 位机器来测试这个,但我可以使用这个测试程序在我的 64 位笔记本电脑上复制相同的行为:

#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;
}

所以你可以在这个程序中看到,不是 &gt;&gt; 操作在进行不需要的符号扩展,而是从 32 位有符号整数转换为 64 位无符号整数,因为转换实际上就像这个:

int32_tint64_tuint64_t

如果你想避免额外的符号扩展,你应该从一个无符号文字开始(正如一些程序员在他的评论中建议的那样),或者强制转换为相同宽度的无符号类型。这些中的任何一个都应该起作用:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-11
    • 2019-07-01
    • 2017-02-27
    • 2013-10-16
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多