&& 运算符的可交换 属性 的问题

Issues with commutative property of && operator

下面我一直遇到奇怪问题的代码旨在 trim 关闭整数数组的未使用部分,然后将其转换为字符串。

例如: _ABC__DE______ 会变成 _ABC__DE.

当输入填充默认字符时出现问题。 (示例中的“_”)。

sLength是整数数组的长度chars

有问题的代码:

  int inputLength = sLength - 1;

  while (chars[inputLength] == defaultChar && inputLength >= 0) {
    inputLength--;
  }

  inputLength++;

  Serial.println("input length: " + String(inputLength));
  // (in)sanity check
  Serial.println(inputLength);
  Serial.println(String(inputLength));
  Serial.println(inputLength <= 0);
  Serial.println(0 <= 0);
  Serial.println(inputLength == 0);
  Serial.println(0 == 0);

  if (inputLength <= 0) {
    //reset cursor position
    Serial.println("index set to 0");
    index = 0;
  } else {
    output = "";
    for (int i = 0; i < inputLength; i++) {
      char c = charSet[chars[i]];
      if (c == '_') {
        c = ' ';
      }
      output += c;
    }
    done = true;
  }

给定数组时的输出 defaultChar:

input length: 0
0
0
0
1
0
1

如果我解释正确,输出意味着偶数行上 0 > 0 和 0 =/= 0,但奇数行上 0 <= 0 和 0 = 0。


我想出的解决方法是替换

  while (chars[inputLength] == defaultChar && inputLength >= 0) {
    inputLength--;
  }

具有以下之一

  while (inputLength >= 0 && chars[inputLength] == defaultChar) {
    inputLength--;
  }

.

  while (chars[inputLength] == defaultChar) {
    inputLength--;
    if (inputLength < 0) {
      break;
    }
  }

两者都导致输出:

input length: 0
0
0
1
1
1
1
index set to 0

为什么这会改变结果? 据我所知,&& 运算符是可交换的。

有什么我遗漏的东西使得

chars[inputLength] == defaultChar && inputLength >= 0

不等于

inputLength >= 0 && chars[inputLength] == defaultChar?

如果相关,这是 运行 在 328P Arduino Nano 上使用旧引导加载程序 IDE 1.8.8

&& 不可交换。它首先评估左操作数,然后在左操作数评估为 0 时停止。

您的原始代码失败,因为在某些时候它计算 chars[-1](如果 chars 是一个数组,则导致 undefined behaviour)。替代版本没有这个问题,因为它在使用 inputLength 作为数组索引之前执行 >= 0 测试。

&& 是可交换的,因为 a && b 的结果与 b && a 的结果相同。但是内置运算符 && 有一个 short-circuiting behavior。这意味着如果 a && b 的结果可以通过单独评估第一个操作数来决定,则不会评估第二个操作数。

因此,当第一个操作数是 chars[inputLength] == defaultChar 并且 inputLength-1 时,您进入了未定义行为的领域,这意味着程序的行为是不可预测的。但是使用变通方法,由于 inputLength >= 0inputLength < 0 检查,您 避免了 未定义的行为,因此代码按预期工作。

正如@PeteBecker 指出的那样:如果 a()b() 有副作用,a() && b() 不可交换。