在这里我想简单的说一个小问题:C语言的赋值运算和求值运算的问题。
可以说这个问题并不是很复杂,有这样一个条件int i = 3 ,j;求j=(++i)+(++i)+(++i);中的j的值是多少?在C当中,实现这段代码并不困难,如下:
#include<stdio.h>
int main(void)
{
int i=3,j;
j=(++i)+(++i)+(++i);
printf("%d\n",j);
return 0;
}
如此简单的一段代码,它的结果是什么呢?我用VC++6.0进行编译,执行的结果是16,用turboc2.0编译,执行的结果18。这并不是乱说,如果你懂得怎么编译一段C的源代码,那么你完全可以找到更多的编译工具,例如:BCB,GCC,来尝试一下结果是什么。但是无论是什么,和我们想象中的结果总是有区别的。因为按照C语言中的规定,++i是先运算后传值的,也就是说当i=3的时候,我们进行了++i后,输出i的值就应该是4,这一点是以上我使用的两个编译器输出的统一结果,相信其他的编译器也不会有什么以外。但是按照这个逻辑推理下j=(++i)+(++i)+(++i)中j的值,那么我们头脑中得到的结果应该是什么呢?首先第一次++i运算后i的值应该是4,第二次结束后应该是5,第三次应该是6,这个结果不知道大家有什么不同的意见吗?如果不信,你可以去编译,但是结果应该是和我们设想的这个是样的,4,5,6。理由也很简单,只因为这是C语言当中的规定。但是按照这个结果算下去,j输出的值不就应该是15吗?怎么有16,或者是18的可能呢?那么如果你按照以下的代码操作,在任何一个C的编译工具中得到的结果都因该是15。
#include <stdio.h>
int main(void)
{
int i=3,j=0;
++i;
j+=i;
++i;
j+=i;
++i;
j+=i;
printf("%d\n",j);
return 0;
}
很多人可能就会发出这样的疑问:这不是和上边的一样吗?只是把一个表达式拆开,变成了多个表达式了吗?怎么结果能不一样呢?那么在这里我告诉你,这两段代码在我们的思想当中是一样的,但是在编译器看来,却是大大的不同的,首先说j=(++i)+(++i)+(++i);这虽然是一句完整的代码,但是严格点说,这是一个赋值的语句,它代表的是将(++i)+(++i)+(++i)的值赋值给j,而并不是一条运算语句,因为在int i=3,j;定义变量j的时候并没有讲j赋初值,也可以说是只定义了j,但是没有初始化变量,对于这个没有初始化的变量j来说,它的值是多少,只有计算机知道,这点是我们要了解的。如果只是这句话,那么,定义变量后赋值和定义变量的时候直接赋值,也就是说int i=3,j=(++i)+(++i)+(++i);这样的赋值方法有什么区别吗?当然这种方法是不可以使用在C当中的,至少是我没有看见有人用这样的语句赋值。好,那么我们看下第二段代码,在这段代码当中,我将j的初值赋为0,虽然没什么必要,但是为了说明以下的问题,就是说以下所做的每一步,都属于一个独立的运算过程,而且是相互关联的运算过程,这个过程就体现了在我们头脑中的运算过程,自加,运算,再自加,在运算,这个程序就体现了我们头脑中的运算思路,所以结果也是一样的j=15。那么这个差距难道就是赋值运算和求值运算的差距这么简单吗?当然不是,这个也不是编译工具的关系,因为这些语句,在便宜器看来是合法的,在我们看来更加是合法的,但是为什么会有这个结果呢?原因,是我们将C的编译器考虑的太万能了。C语言规定了变量运算的优先级,但是并没有定义运算的次序,也就是说在运算(++i)+(++i)+(++i)的时候是按照从左到右的顺序运算出结果将4+5+6的值15赋值给j,还是将++i计算3次,然后将最后的6累加3次的值18赋给j,是c当中是没有定义的,因为这些语句全部都符合语法的规范,编译器也是C的语法规则编译的,这个就很容易解释的通。也就是说变量i在内存中占用一个独立的空间存放它的值,当值别改变的时候依然会存放回这个空间当中,所以进行3次++i运算后的i值就是6,因为前了两次的值4,5已经被覆盖了,原因就是在这个空间上写入了第三次运算的值,然后运算6+6+6,当然就是18了,turboc的结果可以这样解释。但是VC++6.0计算出的16,我是真的很不理解,在这里也希望高手指教,我的理解是,先进行了两次自加运算,这时i在内存中存储的值就是5,然后再进行加法5+5=10,将10先赋值给j,然后再进行第三次的++i,得到的6再和j的值10进行加法运算,将最后的16赋值给j,除了这个方法,我实在是想不到其他的方法解释16这个值的出现,真希望盖茨可以来解释一下。