a = b + (b = a) * 0;

原创 2007年10月07日 20:15:00

这个语句看起来比较奇怪,在C#的编译器中,他的作用是交换a和b的值,而且不会产生数据溢出的问题

在C#的编译器中,对着运算符的执行顺序有着严格的定义,对每个运算符的运算方法也有着严格的定义。

首先读到的第一个运算符是赋值,这个运算符的优先级别比较低,所以继续向后执行,这时遇到遇到的运算符是+,+的方法是自左向右的,编译器把b的值入栈,正是因为这个原因,b的值在内存中被暂存了起来。

+号之后是一个括号,编译器开始对括号里的等式进行编译,a的值被压入了栈中,然后又出栈给了b变量,而对于后面的*0,因为任何数*0之后都会等于0,所以编译器直接就把这一步运算丢弃,同时也丢弃了+0这一步运算,这时就把b的值出栈赋给了a;

这个语句一切前提都是在C#的编译机制的前提下,+号是自左向右的,所以b的值将用入栈的形式被保存下来,而不是先去运算了括号内的赋值。

整个语句因为C#编译器的优化机制,产生的中间代码只有两次入栈,两次出栈,而把计算的步骤优化掉了。我们熟知的借用临时变量交换的方法的三次赋值,则是三次入栈三次出栈,用这个语句可以提高三分之一的效率,可惜的是 a = b + (b = a) * 0只能为数字的类型进行交换,这是局限所在。

一点题外话:
在软件工程学中,不提倡写这样的语句,但是这里对这个语句进行分析的目的,是为了学习C#的运算符运行规则。这个语句的原作者Invoy说得好:虽然在软作中我们不会这么写,但是能看懂这个句子并不是坏事。不过我最喜欢的倒是别外一句:如果说程序没有可读性,当一个语句被写进教科书的时候,可读性的问题也就不存在了。而类似于这种写法简短同时又有效率的语句是完全可以写进教科书的。

最后再写个例子说明运算符的方向规则
a = F(i) + G(i++) + H(i);
C#对+号的运算规则是从左到右,那么不管+右边的优先级有多高,也要把+左边的值计算了再入栈,所以这里i的三次取值,假如开始是3的话,F(i)中是3,G(i++)也是3,到H(i)中就是4了。
在C++中,不同的编译器对上式的运行结果不一样,我们说,这个语句会产生不确定的结果。而C#中严格的定义,我们可以使用这样的技巧。
什么,你说这样的话不能跨平台?拜托,C#是基于framwork的,那玩意儿天下只有一个。 

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)