要讨论这个问题必须先知道几条规则
1.C语言标准规定:=运算符在执行赋值操作前会先对左右操作数进行运算,但是运算的方向不确定可能先算左边后算右边,也有可能先算右边后算左边,赋值操作会在运算完成后执行,且赋值的方向必须为右操作数给到左操作数
2.C语言标准对副作用的规定: 副作用(side effects)是对数据对象或文件的修改,可以简单理解为在表达式对某个变量进行自增和自减行为就会产生副作用
3.C语言对序列点的规定: 序列点(sequence point)是程序执行的点,在该点上,所有的副作用都在进入下一步之前发生。在 C语言 中。意思是,在一个语句中,赋值运算符、递增运算符和递减运算符对运算对象做的改变必须在程序执行下一条语句之前完成,且在俩个连续的序列点中的表达式的副作用发生顺序是不确定的
接下去开始对a[i] = i++;和a[i++] = i;进行讨论
int i = 1 , a[5]= {1,2,3,4,5};
a[i] = i++;
1.首先用优先级对该表达式进行加括号处理(不知道是什么的可以去我主页看叫“关于C语言中表达式运算顺序(优先级、结合性、副作用、序列点)的讨论”的文章)
(a[i]) = (i++);
2.化简为 (XXX) 运算符 (XXX)的形式继续判断运算符的运算顺序
2.1第一次运算为左右操作数进行各自运算,运算顺序不明,由编译器决定运算方向
第一种可能: 先运算左操作数即i++,由于i = 1,i++后会访问i的空间对i中存储的数值进行加1,接着运算左操作数确定此时的i为2即赋值操作时会改变数组a的第3个元素
第二种可能: 先运算左操作数即a[i]确定赋值操作访问的是数组的第2个元素,再对右操作数进行运算即对i存储空间的数据加1最后i结果为 i = 2
2.2第二次运算顺序是明确的,即将右操作数赋值给左操作数
第一种可能: 将变量i中存储的数据2赋值给数组的第三个元素,等价于 a[2] = 2;
第二种可能: 将变量i中存储的数据2赋值给数组的第二个元素,等价于 a[1] = 2;
由此可知a[i] = i++;未定义的行为是由于 = 运算符第一次进行运算时候的方向不确定性影响的,至于a[i++] = i;也是一样的原因大家自己可以去算看看。