为什么赋值运算符不是序列点有什么充分的理由吗?

发布于 2024-10-06 08:09:30 字数 80 浏览 0 评论 0原文

operator = 不作为序列点有什么充分的理由吗?在 C 和 C++ 中都是如此。

我很难思考反例。

Is there any good reason for operator = not being a sequence point? Both in C and C++.

I have trouble thinking about an counter-example.

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

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

发布评论

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

评论(4

等数载,海棠开 2024-10-13 08:09:30

根据请求:

一般来说,事物需要一个理由才能成为序列点。他们不需要理由成为序列点;这是默认值。

例如,由于短路行为,&& 必须是序列点:如果左侧为 false,则不得评估右侧。 (这不仅仅是关于优化;右侧可能会产生副作用,和/或取决于左侧是否正确,如 ptr && ptr->data .) 因此,必须先评估左侧,然后再评估右侧,以便确定是否应该评估右侧。

对于 = 来说,这个原因不存在,因为尽管两边都需要“求值”(虽然两边可以出现的内容有不同的限制:左边必须是左值) - l 不代表“左”,顺便说一句;它代表“位置”,就像内存中的位置一样 - 我们不能分配给临时或文字),它不代表首先评估哪一侧并不重要 - 只要在实际分配之前评估两侧即可。

By request:

In general, things need a reason to be a sequence point. They don't need a reason not to be a sequence point; that's the default.

For example, && must be a sequence point because of short-circuiting behaviour: if the left-hand side is false, the right-hand side must not be evaluated. (This is not just about optimization; the right-hand side could have side effects, and/or depend on the left-hand side being true, as in ptr && ptr->data.) Therefore the left-hand side must be evaluated first, before the right-hand side, in order to see if the right-hand side should be evaluated at all.

This reason does not exist for = because, although there is "evaluation" to do for both sides (although there are different restrictions on what can appear on both sides: the left-hand side must be an lvalue - the l doesn't stand for "left", btw; it stands for "location", as in location in memory - we can't assign to a temporary or a literal), it doesn't matter which side is evaluated first - as long as both sides are evaluated before the actual assignment.

橘香 2024-10-13 08:09:30

是(某种程度上)。 operator=(可以由工程师定义(也称为类类型的用户定义的operator=))只是函数调用的语法糖。因此,它具有与函数调用相同的“序列点”语义。

如果我们正在考虑内置类型,那么我认为这是一件好事。
您不想引入太多序列点,因为这会阻碍优化。

It is (sort of). The operator= (that can be defined by the engineer (aka the user defined operator= for class types)) is just syntactic sugar for a function call. As a result it has the same "sequence point" semantics as a function call.

If we are taking about built in types then I think it is a good thing.
You don't want to introduce too many sequence points as this hinders optimizations.

秋风の叶未落 2024-10-13 08:09:30

有很多理由不要求任何一方先于另一方进行评估。一个更有趣的问题是,在赋值运算符本身执行任何操作之前,是否应该需要对双方进行评估(包括副作用)。我建议这样的要求可以减轻一些别名限制,但在某些情况下需要编译器做更多的工作。例如,假设“foo”和“bar”是指向地址会重叠的大型结构的指针。语句“*foo = *bar;”将代表当前标准下未定义的行为。如果在操作数的求值和赋值之间存在序列点,则这样的语句将保证“有效”。这样的保证将需要更复杂的赋值运算符,需要更大和更慢的代码,即使实际上指针永远不会重叠。

示例:

unsigned char foo[100];
typedef struct {int x, int y;} POINT;
POINT *p1 = (POINT*)foo;
POINT *p2 = (POINT*)(&(p1->y));

鉴于上述声明,我认为以下声明具有指示的严格定义的行为,并且不涉及任何未定义的行为。

  p1->y = somevalue;  // Sets p2->x to somevalue
  p2->x = somevalue;  // Sets p1->y to somevalue
  *p1 = mystruct;     // Sets p2->x to mystruct.y
  *p2 = mystruct;     // Sets p1->x to mystruct.x

然而,以下两条语句将涉及未定义的行为:

  *p1 = *p2;
  *p2 = *p1;

如果等号处有序列点,则编译器必须比较 p1 和 p2,或者将源操作数复制到临时位置,然后将其复制到目的地。然而,该标准明确指出,上述两个语句都被视为未定义行为。该标准要求编译器生成在将结构复制到非重叠结构时正确工作的代码,但对结构重叠时编译器可以执行的操作没有限制。一个编译器,它将处理器发送到一个发送“Frink Rules!”的循环中。每个打开的 TCP 套接字这样做都不会违反标准。

There are many reasons not to require either side to be evaluated before the other. A more interesting question is whether the evaluation of both sides, complete with side-effects, should be required before the assignment operator itself does anything. I would suggest that such a requirement would ease some aliasing restrictions but in some cases require more work for a compiler. For example, suppose "foo" and "bar" are pointers to large structures whose addresses would overlap. The statement "*foo = *bar;" would represent undefined behavior under the current standard. If there were a sequence point between the evaluation of the operands and the assignment, such a statement would be guaranteed to "work". Such a guarantee would require more complicated for the assignment operator, requiring larger and slower code even if in practice the pointers will never overlap.

Example:

unsigned char foo[100];
typedef struct {int x, int y;} POINT;
POINT *p1 = (POINT*)foo;
POINT *p2 = (POINT*)(&(p1->y));

Given the above declarations, I think the following statements have the strictly-defined behaviors indicated and do not involve any Undefined Behavior.

  p1->y = somevalue;  // Sets p2->x to somevalue
  p2->x = somevalue;  // Sets p1->y to somevalue
  *p1 = mystruct;     // Sets p2->x to mystruct.y
  *p2 = mystruct;     // Sets p1->x to mystruct.x

The following two statements, however, would involve Undefined Behavior:

  *p1 = *p2;
  *p2 = *p1;

If there were a sequence point at the equals sign, a compiler would have to either compare p1 and p2, or else copy the source operand to a temp location and then copy it to the destination. The standard, however, makes clear that the above two statements are both considered to be Undefined Behavior. The standard requires compilers to generate code which works correctly when copying a structure to a non-overlapping structure, but places no restriction on what compilers may do if the structures overlap. A compiler which would the processor into a loop sending "Frink Rules!" out every open TCP socket would not violate the standard by so doing.

浅沫记忆 2024-10-13 08:09:30

这是从c++17开始的。
有关详细信息,请参阅

It is since c++17.
See this for details.

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