c++ - 序列点歧义,未定义的行为?

标签 c++ unspecified-behavior

今天我遇到了一些在 clang++ (3.7-git), g++ (4.9.2) 和 Visual Studio 2013。经过一些缩减 我想出了这个突出问题的片段:

#include <iostream>
using namespace std;

int len_ = -1;

char *buffer(int size_)
{
    cout << "len_: " << len_ << endl;
    return new char[size_];
}

int main(int argc, char *argv[])
{
    int len = 10;
    buffer(len+1)[len_ = len] = '\0';
    cout << "len_: " << len_ << endl;
}

g++ (4.9.2) 给出这个输出:

len_: -1
len_: 10

所以 g++ 计算参数给缓冲区,然后是 buffer(..) 本身,然后它计算索引参数给数组运算符。直觉上这对我来说很有意义。

clang (3.7-git) 和 Visual Studio 2013 都给出:

len_: 10
len_: 10

我想 clang 和 VS2013 在它下降到缓冲区(..)之前会评估所有可能的情况。这对我来说不太直观。

我想我的问题的要点是这是否是未定义行为的明显案例。

编辑:感谢您澄清这一点,未指明的行为是我应该使用的术语。

最佳答案

这是unspecified behavior , len_ = len 相对于 buffer() 的主体的执行是indeterminately sequenced的,也就是说会先于其他,但未指定哪个顺序,但有一个顺序,因此评估不能重叠,因此没有未定义的行为。这意味着 gccclangVisual Studio 都是正确的。另一方面,未排序的评估允许重叠评估,这可能导致如下所述的未定义行为。

来自 draft C++11 standard 1.9 部分 [intro.execution]:

[...]Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.9[...]

and indeterminately sequenced 在此之前稍作介绍并说:

[...]Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which. [ Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first. —end note ]

这不同于无序评估:

[...]If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap. —end note ][...]

这可能导致未定义的行为(强调我的):

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. —end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined[...]

C++11 之前

Pre C++11子表达式的求值顺序也未指定,但它使用 sequence points与订购相反。在这种情况下,函数入口和函数导出处有一个序列点,可确保没有未定义的行为。来自 1.9 部分:

[...]The sequence points at function-entry and function-exit (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be.

确定评估顺序

根据您的观点和期望,每个编译器做出的不同选择可能看起来不直观。确定评估顺序的主题是EWG issue 158: N4228 Refining Expression Evaluation Order for Idiomatic C++的主题,正在考虑用于 C++17,但似乎有争议 based on the reactions to a poll on the subject .这篇论文涵盖了更多 complicated case来自“C++ 编程语言”第 4 版。这表明即使是那些在 C++ 方面有丰富经验的人也会被绊倒。

关于c++ - 序列点歧义,未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29513572/

相关文章:

C++ - 默认参数不能添加到类模板成员的外联定义中

c++ - STL Sort静态函数的使用

c++ - 未定义、未指定和实现定义的行为

c++ - 未定义、实现定义、未指定的行为都不是

c++ - 如果 + 运算符重载的第二个操作数在 C++ 中为零,如何返回第一个操作数?

c++ - eclipse 太阳神 - "cannot run program make; unknown reason"

c++ - 与内存相关的莫名其妙的cuda行为

c++ - 我可以获取标准库中定义的函数的地址吗?

c++ - 从字符串数组变量打开文件

c - C的未指定,未定义和实现定义的行为WIKI