关于序列点的解释

发布于 2024-09-30 23:05:16 字数 355 浏览 8 评论 0 原文

最近,我看到很多关于一些疯狂但语法上允许的代码语句的输出的问题,例如 i = ++i + 1i=(i,i++,i) +1;。 坦率地说,现实中几乎没有人在实际编程中编写任何此类代码。坦白说,在我的专业经验中,我从未遇到过此类代码。所以我通常最终会跳过这样的问题。但最近被问到的此类问题的数量之多让我思考我是否因跳过此类问题而错过了一些重要的理论。我推测此类 Q 围绕序列点。坦率地说,我对序列点几乎一无所知,我只是想知道不了解它是否会在某种程度上成为一种障碍。那么有人可以解释一下序列点的理论/概念吗?或者如果可能的话请指出解释该概念的资源。另外,是否值得投入时间来了解这个概念/理论?

Lately, I have seen a lot of questions being asked about output for some crazy yet syntactically allowed code statements like like i = ++i + 1 and i=(i,i++,i)+1;.
Frankly realistically speaking hardly anyone writes any such code in actual programing.To be frank I have never encountered any such code in my professional experience. So I usually end up skipping such questions here on SO. But lately the sheer volume of such Q's being asked makes me think if I am missing out some important theory by skipping such Q's. I gather that the such Q's revolve around Sequence points. I hardly know anything about sequence points to be frank and I am just wondering if not knowing about it is a handicap in some way. So can someone please explain the theory /concept of Sequence points, or If possible point to a resource which explains about the concept. Also, is it worth to invest time in knowing about this concept/theory?

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

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

发布评论

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

评论(5

茶底世界 2024-10-07 23:05:17

是的,序列点的确切技术细节可能会变得很复杂。但遵循这些准则几乎可以解决所有实际问题:

  • 如果表达式修改值,则修改与该值的任何其他使用之间必须存在序列点。
  • 如果您不确定某个值的两次使用是否由序列点分隔,请将代码分解为更多语句。

这里的“修改”包括=+=等中左侧值的赋值操作,也包括++xx++--xx-- 语法。 (通常是这些递增/递减表达式,有些人试图变得聪明,但最终陷入了麻烦。)

幸运的是,在大多数“预期”位置都有序列点:

  • 在每个语句或声明的末尾。
  • 在每个函数调用的开始和结束处。
  • 在内置的 &&|| 运算符处。
  • 在三元表达式中的 ? 处。
  • 在内置的 , 逗号运算符处。 (最常见于 for 条件,例如 for (a=0, b=0; a。)分隔函数参数的不是逗号运算符,也不是序列点。

重载的 operator&&operator||operator, 不会导致序列点。这一事实带来的潜在惊喜是通常不鼓励超载的原因之一。

The exact technical details of sequence points can get hairy, yes. But following these guideline solves almost all the practical issues:

  • If an expression modifies a value, there must be a sequence point between the modification and any other use of that value.
  • If you're not sure whether two uses of a value are separated by a sequence point or not, break up your code into more statements.

Here "modification" includes assignment operations on the left-hand value in =, +=, etc., and also the ++x, x++, --x, and x-- syntaxes. (It's usually these increment/decrement expressions where some people try to be clever and end up getting into trouble.)

Luckily, there are sequence points in most of the "expected" places:

  • At the end of every statement or declaration.
  • At the beginning and end of every function call.
  • At the built-in && and || operators.
  • At the ? in a ternary expression.
  • At the built-in , comma operator. (Most commonly seen in for conditions, e.g. for (a=0, b=0; a<m && b<n; ++a, ++b).) A comma which separates function arguments is not the comma operator and is not a sequence point.

Overloaded operator&&, operator||, and operator, do not cause sequence points. Potential surprises from that fact is one reason overloading them is usually discouraged.

白日梦 2024-10-07 23:05:17

值得了解序列点的存在,因为如果您不了解它们,您可以轻松编写在测试中似乎运行良好但实际上未定义的代码,并且当您在另一台计算机上或使用不同的编译选项运行它时可能会失败。特别是,如果您将 x++ 编写为还包含 x 的较大表达式的一部分,则很容易遇到问题。

我认为没有必要完全学习所有规则 - 但您需要知道何时需要检查规范,或者更好 - 何时重写代码以使其不依赖于序列点规则是否更简单的设计也可以工作。

It is worth knowing that sequence points exist because if you don't know about them you can easily write code which seems to run fine in testing but actually is undefined and might fail when you run it on another computer or with different compile options. In particular if you write for example x++ as part of a larger expression that also includes x you can easily run into problems.

I don't think it is necessary to learn all the rules fully - but you need to know when you need to check the specification, or perhaps better - when to rewrite your code to make it so that you aren't relying on sequence points rules if a simpler design would work too.

尘世孤行 2024-10-07 23:05:17
int n,n_squared;
for(n=n_squared=0;n<100;n_squared+=n+ ++n)
 printf("%i squared might or might not be %i\n",n,n_squared);

...并不总是做你认为会做的事。这会让调试变得很痛苦。
原因是 ++n 检索、修改和存储 n 的值,该值可能是在检索 n 之前或之后。因此,n_squared 的值在第一次迭代后没有明确定义。序列点保证子表达式按顺序求值。

int n,n_squared;
for(n=n_squared=0;n<100;n_squared+=n+ ++n)
 printf("%i squared might or might not be %i\n",n,n_squared);

... doesn't always do what you think it will do. This can make debugging painful.
The reason is the ++n retrieves, modifies, and stores the value of n, which could be before or after n is retrieved. Therefore, the value of n_squared isn't clearly defined after the first iteration. Sequence points guarantee that the subexpressions are evaluated in order.

∞梦里开花 2024-10-07 23:05:16

我能想到的最简单的答案是:

C++ 是根据抽象机定义的。在抽象机上执行的程序的输出仅根据“副作用”执行的顺序来定义。副作用被定义为对 IO 库函数的调用,以及对标记为 volatile 的变量的更改。

C++ 编译器可以在内部做任何他们想做的事情来优化代码,但他们不能改变 volatile 变量和 io 调用的写入顺序。

序列点定义了c/c++程序的心跳——序列点之前的副作用是“完成”的,而序列点之后的副作用尚未发生。但是,副作用(或者,可以间接影响副作用的代码(序列点内)可以重新排序。

这就是为什么理解它们很重要。如果没有这种理解,您对什么的基本理解C++ 程序(以及如何通过激进的编译器对其进行优化)是有缺陷的。

The simplest answer I can think of is:

C++ is defined in terms of an abstract machine. The output of a program executed on the abstract machine is defined ONLY in terms of the order that "side effects" are performed. And Side effects are defined as calls into IO library functions, and changes to variables marked volatile.

C++ compilers are allowed to do whatever they want internally to optimize code, but they cannot change the order of writes to volatile variables, and io calls.

Sequence points define the c/c++ program's heartbeat - side effects before the sequence point are "complete" and side effects after the sequence point have not yet taken place. But, side effects (or, code that can effect a side effect indirectly( within a sequence point can be re-ordered.

Which is why understanding them is important. Without that understanding, your fundamental understanding of what a c++ program is (And how it might be optimized by an agressive compiler) is flawed.

沧笙踏歌 2024-10-07 23:05:16

请参阅http://en.wikipedia.org/wiki/Sequence_point

这是一个非常简单的概念,因此您不需要投入太多时间:)

See http://en.wikipedia.org/wiki/Sequence_point.

It's a quite simple concept, so you don't need to invest much time :)

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