0

我写了一个简单的函数如下......

int fun(int *i, int *j) 
{  
     *i += 3; 
     *j += *i; 
     return (*i + *i); 
}

在主函数中,我按如下方式调用了该函数......

int main()
{
    int x = 3, y = 2, a, b; 
    a = x + y + fun(&x, &y) + x; 
    b = y + fun(&x, &y) + y;

    cout<<" a = " << a << "\n";
    cout<<" b = " << b << "\n";

}

现在的问题是输出不如预期

运行后这是输出

a=23
b=52

我期待

a=23 
b=46

我不知道是否有人可以解释。

4

3 回答 3

5

评估表达式的结果是unspecified,因为 和 的评估xfun(&x, &y)不确定的。

请注意,允许表达式评估产生未指定的结果并不意味着您的程序具有未定义的行为;相反,这意味着您无法判断表达式的评估将产生有限的一组可能结果中的哪一个。

在这里解释标准可能非常棘手(事实上,在最初的答案中,我以错误的方式解释了它 - 感谢Jerry Coffin的注意)。

要了解为什么这很棘手,让我们考虑 C++11 标准第 1.9/15 段的第一部分:

除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的求值是未排序的。[...]运算符的操作数的值计算在运算符结果的值计算之前排序。如果标量对象上的副作用相对于同一标量对象上的另一个副作用或使用同一标量对象的值的值计算是未排序的,则行为是未定义的

例如,给定一个包含计算两个子表达式之和的表达式,例如(考虑operator +这里没有重载):

e1 + e2

如果 的 评估e1使用某个标量 的值s,并且 的评估e2对该值有副作用,则行为未定义。例如,评估:

(i + i++)

由于上面引用的句子,给出了未定义的行为。

但是,您的情况有所不同。稍后的同一段指定:

当调用一个函数时(无论该函数是否是内联的),[...]调用函数(包括其他函数调用)中的每个评估,在被调用函数的主体执行之前或之后没有特别排序关于被调用函数的执行顺序不确定。

这意味着如果要评估的表达式如下所示:

i + f(i)

f(i)increments i,行为不再是 undefined ,而只是unspecified。换句话说,您的编译器可以按任何顺序进行评估if(i)但可能的结果只是这些可能评估之一的结果。

另一方面,如果行为未定义,则可能的结果将是任何结果(从崩溃到按您预期的行为,到在控制台上打印奇怪的消息等等)。

于 2013-05-28T15:16:30.130 回答
1

您的代码有未指定的结果。

未指定表达式中子表达式的求值顺序。因此,在 中x + y + fun(&x, &y) + x;x您在函数调用之外获得的值可能是函数调用x之前的值,也可能是函数调用之后的值。由于您x在它之外有两个不同的地方,一个可能来自函数调用之前,一个来自之后 - 或者两者都可能来自之前,或者两者都可能来自之后。

在进入函数之前和离开函数之前都有一个序列点,所以在x函数外部使用 的值和在函数内部修改它的值之间存在一个序列点。因此,您的行为已定义,但未指定。

从 C++11 开始,“序列点”术语已从标准中删除,取而代之的是“之前排序”、“之后排序”或“相对于未排序”等术语。在这个过程中,在一些以前没有的地方指定了顺序。我不相信之前指定的任何排序(例如进入和退出函数的序列点)已被删除。换句话说,除非我完全弄错了,否则不会改变这种情况。

于 2013-05-28T15:20:51.693 回答
1

考虑下面给出的代码,

x=10;
val=x+f(&x);


void f(int *a)
{
  *a=*a+10;
}

C++ 标准没有定义操作数的左侧是先求值还是右侧求值。因此,如果首先评估左侧,则变量中的值val将为 30,如果首先评估右侧,则该值将为 40。同样的事情也发生在您的代码中。

于 2013-05-28T15:21:43.403 回答