这个问题与我以前的problem有关。我得到的答案是“这是一种未定义的行为。”
请有人解释一下:
示例代码:
int i = 5;
if (--i == i++)
Console.WriteLine("equal and i=" + i);
else
Console.WriteLine("not equal and i=" + i);
//output: equal and i=6
答案 0 :(得分:2)
什么是未定义行为?
任何行为都不是由适当的语言规范明确定义的。有些规范会将某些内容列为明确未定义的内容,但实际上未定义的任何内容都是未定义的。
我怎么知道我的代码有不确定的行为?
希望你的编译器会警告你 - 如果不是这样,你需要阅读语言规范并了解所有有趣的角落案例和角落&导致这些问题的缝隙。
小心那里!
答案 1 :(得分:2)
它在C中未定义,但在C#中定义良好:
来自C#(ECMA-334)规范“运算符优先级和关联性”部分(第14.2.1节):
- 除了赋值运算符和空合并运算符之外,全部 二元运算符留下 - 关联,意味着操作 从左到右执行。 [示例:x + y + z被评估为(x + y)+ z。结束例子]
首先评估--i
,将i
更改为4并评估为4.然后i++
正在评估,将i
更改为5,但评估为4. / p>
答案 2 :(得分:1)
是的,该表达式也是未定义的行为(在C和C ++中)。有关规则的一些信息,请参阅http://en.wikipedia.org/wiki/Sequence_point;您还可以更一般地搜索“序列点”(这是您的代码违反的规则集)。
答案 3 :(得分:1)
(这假定为C或C ++。)
卡尔的回答非常准确。
具体而言,问题是耶利米指出的问题:sequence points。
为了澄清,代码块(--i == ++ i)是单个“发生”。这是一大堆代码,可以同时进行评估。首先没有确定的顺序。可以首先评估左侧,或者可以比较右侧,或者可以比较相等,然后i递增,然后递减。这些行为中的每一个都可能导致此表达式具有不同的结果。这是“未定义”会发生什么。你不知道答案是什么。
将此与声明i = i + 1进行比较;这里,始终首先评估右侧,然后将其结果存储到i中。这是明确的定义。没有歧义。
希望有所帮助。
答案 4 :(得分:1)
在C中,结果是未定义的,在C#中定义了它。
在C中,比较解释为:
以任何顺序完成所有这些:
- 减少i
,然后将i
的值变为x
- 将i
的值计入y,然后增加i
然后比较x和y。
在C#中有更多的操作边界,因此比较被解释为:
减少i
然后将i
的值输入x
然后将i
的值变为y
然后增加i
然后比较x和y。
编译器可以选择在操作边界内完成操作的顺序,因此将相互矛盾的操作置于同一边界内会导致结果未定义。
答案 5 :(得分:0)
因为C标准如此规定。你的例子清楚地表明了一个不确定的行为。
根据评估顺序,比较应为4 == 5
或5 == 6
。然而,条件返回True。
答案 6 :(得分:0)
您之前的问题已被标记为[C],因此我正在回答基于C的问题,即使您当前问题中的代码看起来不像C。
C99中未定义行为的定义表示(§3.4.3):
1未定义的行为
在使用不可移植或错误的程序结构或错误数据时,
本国际标准没有要求
2注意可能的未定义行为包括完全忽略具有不可预测结果的情况,在翻译或程序执行期间以环境特征(有或没有发出诊断消息)的文档方式行事,终止翻译或执行(发出诊断信息)。
C标准的附录J.2有一个(长 - 几页)未定义行为的列表,尽管这仍然不是详尽无遗的。在大多数情况下,未定义的行为意味着您违反了规则,因此了解它的方法是了解规则。
答案 7 :(得分:0)
未定义的行为==无论何时在完全相同的条件下运行结果,结果都不能保证始终相同,或者无论何时使用不同的编译器或运行时执行它,结果都不能保证始终相同。 / p>
在你的代码中,由于它使用的是一个相等的比较运算符,它没有指定首先应该执行操作数的侧,--i
或i++
可能会结束首先运行,你的答案将取决于编译器的实际实现。如果先执行--i
,则会4 == 4
,i = 5;如果首先实施i++
,则会5 == 5
,i = 5。
答案可能结果相同的事实并不妨碍编译器警告您这是一个未定义的操作。
现在,如果这是一种定义左手边(或右手边)应始终首先执行的语言,那么行为将不再是未定义的。