函数参数的计算和函数返回值分配给另一个对象之间是否存在序列点?
换句话说,这是明确定义的行为吗?
int x = 0;
x += func(++x);
我知道函数指示符的计算和函数参数之间以及函数参数和函数内的操作之间存在一个序列点,但是函数参数和基于函数本身的返回值?
标准的编写方式并没有对此给出明确的答案,不同的法学硕士也给出了不同的答案。
来自c23标准:
The following are the sequence points described in 5.1.2.3:
— Between the evaluations of the function designator and actual arguments in a function call
and the actual call. (6.5.2.2).
— Between the evaluations of the first and second operands of the following operators: logical
AND&&(6.5.13); logical OR || (6.5.14); comma , (6.5.17).
— Between the evaluations of the first operand of the conditional ?: operator and whichever of
the second and third operands is evaluated (6.5.15).
— Between the evaluation of a full expression and the next full expression to be evaluated. The
following are full expressions: a full declarator for a variably modified type; an initializer that
is not part of a compound literal (6.7.10); the expression in an expression statement (6.8.3); the
controlling expression of a selection statement (if or switch) (6.8.4); the controlling expression
of a while or do statement (6.8.5); each of the (optional) expressions of a for statement (6.8.5.3);
the (optional) expression in a return statement (6.8.6.4).
— Immediately before a library function returns (7.1.4).
— After the actions associated with each formatted input/output function conversion specifier
(7.23.6, 7.31.2).
— Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call (7.24.5).
我知道函数指示符的求值和函数参数之间有一个序列点,…
不,没有。
...以及函数参数和函数内的操作之间,...
是的,更具体地说,在函数参数的求值和函数调用之间,根据 C 2024 6.5.3.3:
…在函数指示符和实际参数的求值之后但在实际调用之前有一个序列点…
…但是函数参数和基于函数本身的返回值的变量赋值之间又如何呢?
没有明确指出,但函数必须在
return
语句中包含至少一个完整表达式,并且其后有一个序列点。该序列点位于函数参数求值之后、在 x
中分配 x += …
之前。
但是,这些都不是编译器抱怨的。复合赋值
x += func(++x)
等价于 x = x + func(++x)
,只不过对于 xx
=in that rewriting. So the right side of
xcontains both a use of
xand a separate modification of
++x` 的前两次出现,(in
的左值仅计算一次),并且这两个操作彼此之间没有顺序。
由于使用了复合赋值运算符,这实际上是未定义的行为。
a += b
形式的表达式与 a = a + b
完全相同,只是 a
仅计算一次。 这意味着:
x += func(++x);
本质上与此相同:
x = x + func(++x);
并且看上面的内容,很明显,左侧
x
的评估与++
作为函数参数的副作用之间没有序列点。