C#:function评估顺序(vs C)

请使用以下C代码( K&R第77页 ):

push(pop() - pop()); /* WRONG */ 

这本书说,因为-/不是可交换的运算符,所以评估2个pop函数的顺序是必要的(显然,为了获得正确的结果)……因此你必须将第一个函数的结果放入先变量,然后继续算术,如下:

 op2 = pop(); push(op2 - pop()); 

显然这是因为编译器无法保证评估函数的顺序(…为什么?)


我的问题是,C#做同样的事吗? 在使用C#时,我是否需要担心这种事情? 就此而言,任何其他更高级别的语言?

在C#中它是从左到右: http : //blogs.msdn.com/oldnewthing/archive/2007/08/14/4374222.aspx


Re:C ++订单

显然这是因为编译器无法保证评估函数的顺序(…为什么?)

任何特定的编译器都可以保证订单。 问题是语言规范没有指定顺序,所以每个编译器都可以做任何想做的事情。 这意味着如果要保证排序,则必须在两个方法调用之间添加一个序列点。

为了回答你关于为什么C没有定义操作顺序的问题,这只是因为C的发明者认为给编译器实现者提供优化表达式评估的机会是有价值的。 他们还认为这比给予程序员表达评估的确定性更有价值。

请记住,当C最初开发时,机器的能力远远低于今天,并且更有兴趣为编译器提供优化余地。 今天,通常会给予更安全,更可预测的代码更多的权重。

从编码中的神话般冒险:优先级与关联性与顺序 :

另一种看待它的方法是C#中的规则不是“先做括号”,而是用括号括起来然后递归地应用规则“评估左侧,然后评估右侧,然后执行操作”。

不,C#不会做同样的事情。 它不像C那样使用评估边界,其中边界之间的执行顺序是未定义的。 表达式从左到右进行评估,正如您所期望的那样。

如果您不确定执行的顺序,或者您希望使代码更清晰,则应使用局部变量作为中间结果。 局部变量的分配非常便宜,因为它们在堆栈上分配,在某些情况下,编译器甚至能够将变量放入寄存器中,以便根本不分配它。 此外,根据表达式的外观,编译器可能需要使用局部变量来存储intermediade结果。

这本书说,因为 – 和/不是可交换的运算符,所以评估2个pop函数的顺序是必要的(显然,为了获得正确的结果)……因此你必须将第一个函数的结果放入先变量,然后继续算术。

那不太正确。 K&R允许重新排列交换运算符( 在ANSI C中完成 )。 由于suibtraction 不是可交换的,所以它不能重新安排……至少在这个规则下。

(联合国)幸运的是,C 没有定义评估的顺序 (在一个相当小的范围之外 ) – 这意味着编译器可以按任何顺序调用这些函数(只要pop() - pop()是在调用push()之前完全评估

哪个 – 在这种情况下,导致相同的问题 – 但出于不同的原因。

在所有情况下,评估顺序在C#中都是明确定义的,并且从左到右。 来自C#语言规范(§7.3):

表达式中运算符的求值顺序由运算符的优先级和关联性决定(第7.2.1节)。 表达式中的操作数从左到右进行计算。 例如,在F(i)+ G(i ++)* H(i)中,使用旧值i调用方法F,然后使用旧值i调用方法G,最后调用方法H与i的新价值。 这与运算符优先级分开并且与运算符优先级无关

在C ++的情况下,并不是订单无法定义; 允许编译器未定义允许编译器更好地优化代码。

我相信在C#中,参数列表按从左到右的顺序进行评估。

让我感到惊讶,但显然C#做了“正确”的事情,并从左到右进行评估:

 void Main() { Console.WriteLine(Pop() - Pop()); // Prints -1 } // Define other methods and classes here bool switchVar = true; int Pop() { int ret; if (switchVar) ret = 1; else ret = 2; switchVar = !switchVar; return ret; }