意外的求值顺序(编译器错误?)

发布于 2024-10-20 17:37:53 字数 614 浏览 0 评论 0原文

可能的重复:
未定义的行为和序列点

我不确定这是否是 gcc bug ,所以我会问:

unsigned int n = 0;
std::cout << n++ << n << ++n;

gcc 给出了极其奇怪的结果: AFAICT不可能的“122”。因为<<是左关联的,它应该与:

operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

并且因为在评估参数之前和之后都有一个序列点,所以两个序列点之间的 n 永远不会被修改两次(甚至不会被访问)——所以它不应该是未定义的行为,只是评估顺序未指定。

所以 AFAICT 有效结果将是: 111 012 002 101

,没有别的

Possible Duplicate:
Undefined Behavior and Sequence Points

I'm not sure if this is a gcc bug or not, so I'll ask:

unsigned int n = 0;
std::cout << n++ << n << ++n;

gcc gives the extremely strange result:
"122" which AFAICT is impossible. Because << is left associative, it should be the same as:

operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

and because there is a sequence point before and after evaluating arguments, n is never modified twice (or even accessed) between two sequence points -- so it shouldn't be undefined behaviour, just the order of evaluation unspecified.

So AFAICT valid results would be:
111
012
002
101

and nothing else

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

洛阳烟雨空心柳 2024-10-27 17:37:53

计算参数和调用函数之间有一个序列点。评估不同参数之间没有顺序点。

我们看一下最外层的函数调用:

operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

参数是

  • operator<<(operator<<(std::cout, n++), n)

  • ++n

。未指定首先评估其中哪一个。还允许在计算第二个参数时部分计算第一个参数。

根据标准的 [intro.execution] 部分(草案 3225 中的措辞):

  • 如果A之前没有被测序
    BB 未在 A 之前排序,则 AB 是 < em>未排序。 [ 注意: 未排序的执行
    评估可能会重叠。 - 尾注]

  • 除非另有说明,否则对各个运算符的操作数和各个子表达式的求值
    表达式是无序的。 [ 注意: 在执行期间多次求值的表达式中
    对于一个程序,其子表达式的无序和不确定顺序的求值不需要
    在不同的评估中表现一致。 — end note ] 操作数的值计算
    运算符在运算符结果的值计算之前被排序。如果对标量有副作用
    相对于同一标量对象上的另一个副作用或值计算,对象是无序的
    使用同一标量对象的值,行为是未定义的。

因为您对同一个标量对象有多个具有副作用的操作,并且这些操作彼此之间没有顺序,所以您处于未定义行为的领域,甚至 999 也是允许的输出。

There is a sequence point between evaluating arguments and calling a function. There is no sequence point between evaluating different arguments.

Let's look at the outermost function call:

operator<<(operator<<(operator<<(std::cout, n++), n), ++n)

The arguments are

  • operator<<(operator<<(std::cout, n++), n)

and

  • ++n

It is unspecified which of these is evaluated first. It's also allowed that the first argument is partially evaluated when the second argument is evaluated.

From the standard, section [intro.execution] (wording from draft 3225):

  • 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.

Because you have multiple operations with side effects on the same scalar object which are unsequenced with respect to each other, you're in that realm of undefined behavior, and even 999 would be a permissible output.

羁〃客ぐ 2024-10-27 17:37:53

编译器错误的第一条规则:这可能不是编译器错误,而是您的误解。在同一语句中使用后缀和前缀运算符会导致未定义的行为。尝试使用 -Wall 选项向您提供更多警告并显示代码中的潜在陷阱。

让我们看看当我们请求有关 test.cpp 的警告时,GCC 4.2.1 告诉我们什么:

#include <iostream>

int main() {
    unsigned int n = 0;
    std::cout << n++ << n << ++n << std::endl;
    return 0;
}

当我们编译时:

$ g++ -Wall test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:5: warning: operation on ‘n’ may be undefined

The first rule of compiler bugs: it's probably not a compiler bug but a misunderstanding on your part. Using the postfix and prefix operators in the same statement results in undefined behavior. Try using the -Wall option to give you more warnings and show you the potential pitfalls in your code.

Let's see what GCC 4.2.1 tells us when we ask for warnings about test.cpp:

#include <iostream>

int main() {
    unsigned int n = 0;
    std::cout << n++ << n << ++n << std::endl;
    return 0;
}

When we compile:

$ g++ -Wall test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:5: warning: operation on ‘n’ may be undefined
小草泠泠 2024-10-27 17:37:53

您的代码是为什么在一些书中评论经验丰富的程序员不喜欢 that(++,--) 运算符重载的一个例子,即使其他语言(ruby)还没有实现 ++ 或 -- 。

Your code its an example of why in some books remark that experienced programmers don't like that(++,--) operator overload, even other languages (ruby) has not implemented ++ or --.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文