令我困惑的是,CPPReference说后增量的价值判断是在副作用之前排序的,而预增量却没有这样的保证.
我现在举了一个例子,说明这一点很重要,但我不确定我的分析是否正确.
据我所知,这两个程序的不同之处在于,第一个程序包含UB,而第二个程序不包含:
#include <stddef.h>
#include <stdio.h>
int main(void) {
int arr[] = {0, 1, 2};
int i = 1;
int x = ++arr[arr[i]];
}
#include <stddef.h>
#include <stdio.h>
int main(void) {
int arr[] = {0, 1, 2};
int i = 1;
int x = arr[arr[i]]++;
}
我对表达式++arr[arr[i]]
的分析如下:
- There are these sequenced-before relations:
- 值计算
i
在值计算arr[i]
之前进行排序 - 值计算
arr[i]
在值计算arr[arr[i]]
之前进行排序 - 值计算
arr[arr[i]]
在值计算++arr[arr[i]]
之前进行排序
- 值计算
- 关于这些,
++arr[arr[i]]
的副作用是没有顺序的. - 编译器可以 Select 满足这些关系的任何顺序,并且可以删除
arr[arr[i]]
的值计算,因为它不被使用. - 在任何可能的顺序中,
arr[arr[i]]
的值计算引用与arr[i]
相同的标量对象. -
++arr[arr[i]]
的副作用修改了标量对象arr[arr[i]]
,但它的访问顺序与arr[i]
的访问顺序不同.
然而,如果我们使用后增量,我们引入了一个新的sequenced-before关系:arr[arr[i]]++
的值计算顺序在其副作用之前.因此,通过传递性,副作用不再是无序的arr[i]
.
然而,我不确定这是否准确.特别是,我不确定如何准确定义递增后/递增前的判断.它是否执行其操作数的值计算?如果是,这是否意味着++*ptr
是UB,而(*ptr)++
不是UB?如果没有,如何执行完整表达式的值计算-任何运算符都可以访问左值表达式的值,而不对该表达式执行值计算吗?