[英]Using increment in ternary operator in C
例如,我使用后
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。
为什么会发生这种情况,为什么在第一种情况下不执行增量运算符?
编辑:只是为了澄清,我问为什么当我分别使用这些线,一个接一个,而不是所有三个同时使用这些线时。
a = (a < b) ? a++ : b++;
在这里,我们存储了一个,然后递增它。 但它就像
a = a++; // as a<b
显示未定义的行为。
a = (a++ < b++) ? a : b;
这里,a在比较时递增,所以现在a是6,它存储在a中。
这两种情况都涉及某种不确定的行为,因为你递增a
,返回a
和分配到a
在2个序列点左侧。 明确定义的结果需要3。
在这种情况下: a = (a < b) ? a++ : b++;
a = (a < b) ? a++ : b++;
a
小于b
a
被返回(值= 5)作为三元运算的结果 a
递增(值= 6)。 a
(重写6) 步骤3和4的顺序未定义。 它相当于a = a++;
在这种情况下: a = (a++ < b++) ? a : b;
a = (a++ < b++) ? a : b;
a
小于b
a
和b
递增(不管哪个更小) a
作为三元运算符的结果返回 a
步骤2和3的顺序没有明确定义。
在这种情况下跟踪序列点很重要。 相关规则:
?
在第2或第3个表达式之前排序。 并且在分配之前对其中任何一个进行排序。 ?
之前排序的?
a++
这样a++
表达式中,在递增之前返回值 未定义的行为:
a = a++;
表达式中a = a++;
有递增之间(后)没有序列点a
和分配到a
在左侧。 两者都在返回a
的原始值之后发生 a++ ? a : b
这样a++ ? a : b
表达式中a++ ? a : b
a++ ? a : b
在(后)递增a
和从三元运算符返回a
之间没有序列点。 两者都发生在?
之后?
给你意想不到的结果的一行有一个错误:你不允许在同一个表达式中修改一个对象(这里a
)两次而不用“序列点”将它们分开。
的?
在另一个是序列点,所以一个工作。
如果这样做(在没有序列点的情况下修改两次),程序的行为将变为未定义。 也就是说,你无法对程序应该产生什么做出任何合理的假设,因此你会看到一些意想不到的结果,甚至会根据编译器及其版本而有所不同。
从马的嘴里 :
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++
的评估之间存在一个序列点,但在=
运算符的LHS和a++
的a
的评估之间没有序列点; 因此,行为是不确定的。
在表达中
a = (a++ < b++) ? a : b
之间存在序列中的点(a++ < b++)
和a
上的所述RHS ?
操作者,但有在之间没有序列点a
上的LHS =
操作者和(a++ < b++)
; 再次,行为是不确定的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.