例如,在我使用
之后int a = 5, b = 6;
x = (a < b) ? a++ : b++;
x获取a的值,即5,增量为6,这是预期的。
当我使用
时a = (a < b) ? a++ : b++;
在这一行之后,仍然是5。
但是
a = (a++ < b++) ? a : b;
a现在是6。
为什么会发生这种情况?为什么在第一种情况下不执行增量运算符?
编辑:只是为了澄清,我问为什么当我分开使用这些行时,一个接一个,而不是同时使用这三行。
答案 0 :(得分:4)
function func() {
var b = document.getElementById("abc");
var a= b.options[b.selectedIndex].value;
$('input.ok').attr('id', a);
$('#' + a).on('click', function(e){
// do something
});
}
在这里,我们将 a 存储在a中,然后将其递增。但它就像
a = (a < b) ? a++ : b++;
显示未定义的行为。
a = a++; // as a<b
这里,a在比较时递增,所以现在a是6,存储在a中。
答案 1 :(得分:2)
这两种情况都涉及某种类型的未定义行为,因为您正在递增a
,返回a
并在2个序列点内分配到左侧的a
。明确定义的结果需要3个。
在这种情况下:
a = (a < b) ? a++ : b++;
a
小于b
a
(值= 5)
a
递增(值= 6)。a
(覆盖6)未定义步骤3和4的顺序。它相当于a = a++;
在这种情况下:
a = (a++ < b++) ? a : b;
a
小于b
a
和b
会递增(无论哪个更小)a
作为三元运算符a
步骤2和3的顺序没有明确定义。
在这种情况下跟踪序列点非常重要。相关规则:
?
左侧的三元运算符的第一个表达式在第二个或第三个表达式之前排序。并且在分配之前对其中任何一个进行了排序。?
a++
之类的表达式中,在递增未定义的行为:
a = a++;
这样的表达式中,(post)递增a
和分配到a
左侧之间没有序列点。两者都发生在返回a
的原始值a++ ? a : b
这样的表达式中,(post)递增a
和从三元运算符返回a
之间没有序列点。两者都发生在?
答案 2 :(得分:1)
给你意想不到的结果的一行有一个错误:你不允许在同一个表达式中修改一个对象(这里a
)两次而不用“序列点”将它们分开。
另一个中的?
是序列点,因此可以使用。
如果这样做(在没有序列点的情况下修改两次),程序的行为将变为未定义。那就是你无法对程序应该产生什么做出任何合理的假设,因此你会看到一些意想不到的结果,甚至会根据编译器及其版本而有所不同。
答案 3 :(得分:0)
6.5表达式
...
2如果相对于不同的副作用,对标量对象的副作用未被排序 在相同的标量对象上或使用相同标量的值进行值计算 对象,行为未定义。如果有多个允许的排序 表达式的子表达式,如果这样一个未经测序的一方,则行为是不确定的 效果发生在任何排序中。 84) 84)此段落呈现未定义的语句表达式,例如同时允许i = ++i + 1; a[i++] = i;
i = i + 1; a[i] = i;
6.5.15条件运算符
...
4评估第一个操作数; 评估与评估之间存在一个序列点 评估第二或第三操作数(以评估者为准)。第二个操作数 仅当第一个比较不等于0时才计算;第三个操作数仅在以下情况下进行评估 第一个比较等于0;结果是第二个或第三个操作数的值 (无论哪个被评估),转换为下述类型。 110) 110)条件表达式不产生左值。
6.5.16分配运营商
...
3赋值运算符将值存储在左操作数指定的对象中。一个 赋值表达式具有赋值后的左操作数的值, 111)但不是 一个左值。赋值表达式的类型是左操作数将具有的类型 在左值转换后。更新左操作数的存储值的副作用是 在左右操作数的值计算之后排序。 评估 操作数没有排序。 111)允许实现读取对象以确定值,但不是必需的 当对象具有volatile限定类型时。
在表达式
中a = (a < b ) ? a++ : b++
(a < b)
和a++
的评估之间存在一个序列点,但a
运算符的LHS上=
的评估之间没有序列点和a++
;因此,行为是不确定的。
在表达式
中a = (a++ < b++) ? a : b
(a++ < b++)
运算符的RHS上a
与?
之间存在一个序列点,但a
之间没有序列点=
运算符和(a++ < b++)
的LHS;再次,行为是不确定的。