我只知道i = i++;
是未定义的行为,但是如果表达式中调用了两个或多个函数,并且所有函数都相同。它是未定义的吗?例如:
int func(int a)
{
std::cout << a << std::endl;
return 0;
}
int main()
{
std::cout << func(0) + func(1) << std::endl;
return 0;
}
表达式func(0) + func(1)
的行为定义为,结果将是参数为 0
调用 func
和参数为 1
的 func
获得的结果之和。
但是,调用函数的顺序可能取决于实现,尽管它可能未指定。也就是说,编译器可以生成等效于以下内容的代码:
int a = func(0);
int b = func(1);
int result = a + b;
或者它可以生成:
int a = func(1);
int b = func(0);
int result = a + b;
这通常不会成为问题,除非func
具有取决于调用顺序的副作用。
std::cout << func(0) + func(1) << std::endl;
函数调用是func(0)
先执行还是先执行func(1)
取决于实现。之后,有一个序列点,输出func(0) + func(1)
。
但根据定义,它不被称为未定义的行为。
如果我们查看草案C++标准部分,该程序的行为不是未定义的,而是未指定的1.9
程序执行第15段说(强调我的):
除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的计算是无序的。[ 注意:在程序执行期间多次计算的表达式中,其子表达式的未排序和不确定顺序计算不需要在不同的计算中一致地执行。运算符操作数的值计算在运算符结果的值计算之前进行排序。如果对标量有副作用 对象相对于同一标量对象上的另一个副作用或使用同一标量对象的值进行值计算是未排序的,行为是未定义的。
如果我们检查涵盖+
5.7
加法运算符部分,并且-
该部分没有指定排序,因此它是未排序的。
在这种情况下,func
有一个副作用,因为它输出到stdout
,因此输出的顺序将取决于实现,甚至可能会在后续评估中发生变化。
请注意,;
结束了表达式语句,6.2
表达式语句部分说:
[...]表达式语句的所有副作用在执行下一条语句之前完成。[...]
因此,尽管未指定函数调用的顺序,但每个语句的副作用在下一个语句之前完成。