hac*_*cks 6 c undefined-behavior sequence-points
标准规定:
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算来修改一次.此外,只能访问先前值以确定要存储的值.
在例子中
i = i++;
a[i] = i++;
Run Code Online (Sandbox Code Playgroud)
从声明的第一句可以清楚地看出,这些例子是未定义行为的结果.
在解释声明的第二句时,据说;
第二句话说:如果一个对象被写入一个完整的表达式,那么同一个表达式中对它的任何和所有访问都必须直接参与计算要写入的值.此规则有效地将法律表达式约束为在修改之前明显存在访问的表达式.例如,旧备用
i = i + 1
Run Code Online (Sandbox Code Playgroud)
是允许的,因为i的访问用于确定i的最终值.这个例子
a[i] = i++
Run Code Online (Sandbox Code Playgroud)
是不允许的,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(在i ++中发生),因此没有好的方法来定义.
我的问题是;
1.它是什么意思,如果一个对象被写入一个完整的表达式,那么在同一个表达式中对它的任何和所有访问必须直接参与计算要写入的值.?
2.它是什么意思,该示例a[i] = i++
是不允许的,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(在i ++中发生)
可能有人以一种简单的方式解释它吗?
我的问题是; 1.它是什么意思,如果一个对象被写入一个完整的表达式,那么在同一个表达式中对它的任何和所有访问必须直接参与计算要写入的值.
有一个子表达式i++,i写入.而且,赋值是一个表达式,因此i = 2,i写入.a = b表达可能不是很明显,但确实如此.这就是为什么你可以做的事情a = b = c,这是好的,if (a = b)哪些不太好.
所以它说的是,如果你写入i,使用=,或预先或后增加,那么对i的任何访问必须作为i的新值的计算的一部分.然而,这很重要,计算前后增量所涉及的唯一事情是i 语句开头的值.
2.它是什么意思,例子a [i] = i ++被禁止,因为i的一个访问(a [i]中的一个)与最终存储在i中的值无关(其中发生在i ++)
正是它所说的.当您访问i的a[i]是不是新的价值计算的一部分i,从结果i++.
有人可以用一些简单的方法解释它吗?
简单方法:不要在表达式中使用前置或后置增量.总是在声明中自己使用它们.如果你真的必须,请不要在整个语句中的任何其他地方使用相同的变量.
最后我得到了关于这一点的解释。阅读完它和常见问题解答后, 我得出的结论是:
1.最后一句话
此外,仅应访问先前值以确定要存储的值
会是这样的;
此外,仅应访问对象的先前值以确定要存储的( 同一对象的)修改/新值。
从例子中可以清楚地看出
int i = 1, j, a[5];
i = i + 1;
j = i + 1;
a[i] = i;
Run Code Online (Sandbox Code Playgroud)
在表达式的情况下,访问(在 RHS 中)的i = i + 1先前值(此处)以确定要存储 的值,这就是语句的内容1ii
如果在完整表达式中写入对象,则同一表达式中对其的任何和所有访问都必须直接参与要写入的值的计算。
说。 而在和
的情况下,访问的值 只是值而不是先前的值,因为 这些语句中没有修改任何位置。j = i + 1a[i] = ii i
2.第二个问题可以解释为;
如果是表达式a[i] = i++or a[i++] = i,则上述语句的第一句
在上一个和下一个序列点之间,对象的存储值最多应通过表达式的求值修改一次。
获取失败,因为 在两个连续序列点之间仅i 修改一次。这就是为什么我们需要第二句话。
这两个例子在 C 中都是不允许的,因为 的先验值被 i 访问两次,即i++ 它本身访问 表达式中的 先验值来修改它,因此对先验值/ 的值的 其他访问 是不必要的,因为不会访问它来确定修改的值要存储的值。 ii