为什么 (( cout << ptr; cout << "\n" << ++ptr; )) 和 (( cout << ptr << "\n" << ++ptr; )) 会给出不同的结果?

3

我是c++的新手,最近花了几天时间研究指针。我发现下面两段代码看起来完全相同,但结果却不同。

第一段代码:

int a = 5;
int* ptr = &a;
cout << ptr;
cout << "\n" << ++ptr;

第二段代码:
int a = 5;
int* ptr = &a;
cout << ptr << "\n" << ++ptr;

以下是第一个的输出:

0043F940
0043F944

以下是第二个的输出:

003AFE20
003AFE20

对我来说,第一个输出似乎更合理,因为它首先输出了a的地址,然后是下一个整数位置的地址。但在第二个输出中,ptr显然始终指向a
有人能解释一下这种差异吗?
非常感谢。


1
第二段代码片段存在未定义行为,因为函数参数的求值顺序是不确定的。 - Vlad from Moscow
1
“但在第二个例子中,指针ptr 显然始终指向a。你是如何确定的?难道你只是将增加后的值输出了两次吗?” - David Schwartz
正如@VladfromMoscow所指出的那样,顺序是未定义的。因此,++ptr首先被评估,然后再次评估ptr,具有相同的值。它们可能不指向a,而是指向下一个位置。您可以使用cout <<&a来验证这一点。 - Mirko
@VladfromMoscow:不再适用于C++17(OP没有使用),请参见https://en.cppreference.com/w/cpp/language/eval_order。 - Jarod42
重新打开。所谓的重复与此问题无关。 - Pete Becker
谢谢大家的评论和回答。我没有注意到这与评估顺序有关,这就是为什么我在网上找不到任何答案,而且我认为可能是Visual Studio的错误。感谢您抽出时间来回答,对于重复问题表示抱歉 :) - Mohammad Parvari
2个回答

2
请注意以下代码:cout << ptr << "\n" << ++ptr; 您的代码类似于f (ptr, ++ptr);,它们都存在同样的问题。
这两行代码中都有两个地方读取了ptr的值,并且有一个地方写入ptr的值。虽然++ptr的读取必须在写入之前进行,但是ptr的读取(对于<< ptrf的第一个参数)没有限制,可以在写入之前或之后进行。
这是因为C++不指定函数参数的评估顺序。显然,在您的平台上,使用您的编译器标志,增量恰好发生在另一个读取之前。因此,您输出了增加后的值两次。

请注意,C++17对于E1 << E2强制执行评估顺序。 - Jarod42

1
让我们将operator<<(a, b)命名为函数f(a, b)。使用这个符号表示法,cout << 5变成了f(cout, 5)。利用<<运算符的从左到右结合性,cout << 4 << "a"变成了f(f(cout, 4), "a")
让我们翻译你的代码:
cout << ptr << "\n" << ++ptr;

至:

f(f(f(cout, ptr), "\n"), ++ptr);

正如您所看到的,对于函数 f 的最外部调用在第二个参数中有 ++ptr。由于 C++ 没有规定函数调用参数的计算顺序,因此它可以在计算嵌套的 f(...) 函数调用之前先对 ptr 进行递增操作。

请注意,C++17对于E1 << E2强制执行评估顺序。 - Jarod42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接