左移<<如何在不同的功能中给出不同的结果?

sci*_*lot 2 c++ bit-shift bitwise-operators

我一直在调试 C++ 库中的一个问题,发现文字 0设置为 0仅在库内部的变量之间存在奇怪的差异。如果我将代码复制到我自己的代码中,它会按预期工作。

库代码正在1向下移动一个长整数以一次屏蔽一位。发送某个代码(REPEAT 键)时,您会发送一种虚拟数据包,并且“没有位”,因此它传输标头而不传输数据。我假设如果没有要发送的位,for 循环将跳过循环。

我已经简化了它以分解分配,并添加了以下调试。我只是重复这两个步骤nbits0我添加的文字。

void  IRsend::sendNEC (unsigned long data,  int nbits){

    Serial.println(data, HEX);
    Serial.print(" nbits = ");
    Serial.println( nbits);
    if(nbits == 0) Serial.println("nbits == 0"); else Serial.println("nbits != 0 "); 
    Serial.print(" 0 - 1 = ");
    Serial.println(0 - 1);
    Serial.print(" nbits - 1 = ");
    Serial.println(nbits - 1);
    Serial.print(" (1UL << (0 - 1) = ");
    Serial.println(1UL << (0 - 1));
    Serial.print(" (1UL << (nbits - 1) = ");
    Serial.println(1UL << (nbits - 1));
    ...

    // the part I was originally debugging:
        for (unsigned long  mask = 1UL << (nbits - 1);  mask;  mask >>= 1) {
    ...
}

called like:

  irsend.sendNEC(0xFFFFFFFF, 0);

Run Code Online (Sandbox Code Playgroud)

这令人惊讶地给出了以下输出:

FFFFFFFF
 nbits = 0
 nbits == 0
 0 - 1 = -1
 nbits - 1 = -1
 (1UL << (0 - 1) = 0
 (1UL << (nbits - 1) = 1
Run Code Online (Sandbox Code Playgroud)

最后两个结果怎么可能不同?nbit是 0,那么为什么文字 0 在最终都为 -1 时会发生不同的变化(我添加了额外的括号以确保)?

为什么,当我将完全相同的调试代码复制到调用该库的代码中,并调用如下测试函数时:

void runtest(unsigned long data,  int nbits){
/// same debug ... 
}
void setup() {
  runtest(0xFFFFFFFF, 0);
}

Run Code Online (Sandbox Code Playgroud)

我得到预期的输出:

-- Same test again --
FFFFFFFF
 nbits = 0
nbits == 0
 0 - 1 = -1
 nbits - 1 = -1
 (1UL << (0 - 1) = 0
 (1UL << (nbits - 1) = 0
Run Code Online (Sandbox Code Playgroud)

我只能准确地猜测 0 == 0,例如,如果它默认为更长的类型 0?

这是使用 Arduino IRRemote 库:https : //github.com/z3t0/Arduino-IRremote/blob/master/ir_NEC.cpp

它在 ATmega328 上运行,我在 MacOSX 上构建,大概是在 Arduino 1.8.10 IDE 中使用 avr-gcc。

Mat*_*Mat 5

从 C++ 标准草案expr.shift

操作数应为整数或无作用域枚举类型,并执行整数提升。结果的类型是提升的左操作数的类型。如果右操作数为负数,或者大于或等于提升的左操作数的宽度,则行为未定义

您的代码具有未定义的行为,因此任何事情都可能发生。