&& 运算符的可交换 属性 的问题
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 >= 0
和 inputLength < 0
检查,您 避免了 未定义的行为,因此代码按预期工作。
正如@PeteBecker 指出的那样:如果 a()
或 b()
有副作用,a() && b()
不可交换。
下面我一直遇到奇怪问题的代码旨在 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 >= 0
和 inputLength < 0
检查,您 避免了 未定义的行为,因此代码按预期工作。
正如@PeteBecker 指出的那样:如果 a()
或 b()
有副作用,a() && b()
不可交换。