什么是序列点,它们与未定义的行为有何关系?

发布于 2025-02-12 02:45:42 字数 890 浏览 2 评论 0 原文

什么是“序列点”?

未定义的行为和序列点之间的关系是什么?

我经常使用有趣且令人费解的表情,例如 a [++ i] = i; ,以使自己感觉更好。我为什么要停止使用它们?

如果您已经阅读了本文,请务必访问后续问题 不确定的行为和序列点重新加载


(Note: This is meant to be an entry to Stack Overflow's C++ FAQ. If you want to critique the idea of providing an FAQ in this form, then the posting on meta that started all this would be the place to do that. Answers to that question are monitored in the C++ chatroom, where the FAQ idea started out in the first place, so your answer is very likely to get read by those who came up with the idea.)

What are "sequence points"?

What is the relation between undefined behaviour and sequence points?

I often use funny and convoluted expressions like a[++i] = i;, to make myself feel better. Why should I stop using them?

If you've read this, be sure to visit the follow-up question Undefined behavior and sequence points reloaded.



(Note: This is meant to be an entry to Stack Overflow's C++ FAQ. If you want to critique the idea of providing an FAQ in this form, then the posting on meta that started all this would be the place to do that. Answers to that question are monitored in the C++ chatroom, where the FAQ idea started out in the first place, so your answer is very likely to get read by those who came up with the idea.)

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

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

发布评论

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

评论(6

我不会写诗 2025-02-19 02:45:43

C ++ 98和C ++ 03

此答案适用于C ++标准的较旧版本。 C ++ 11和C ++ 14版本的标准版本不正式包含“序列点”;操作是“在”之前“测序”或“未序列”或“不确定测序”。网基本上是相同的,但是术语是不同的。


免责声明:tl'dr。

前提条件


什么是序列点?

标准说

在执行序列中的某些指定点,称为序列点,所有
应完成,并且不得进行随后评估的副作用。 (§1.9/7)


副作用?什么是副作用?

对表达式的评估会产生某些东西,如果另外,执行环境的状态发生了变化,则据说表达式(其评估)具有一定的副作用。

例如:

int x = y++; //where y is also an int

除了初始化操作外,由于+> ++ 运算符的副作用, y 的值也会更改。

到目前为止,一切都很好。转到序列点。 Comp.lang.c作者给出的SEQ点的交替定义 Steve Summit

序列点是灰尘沉降的时间点,到目前为止已经看到的所有副作用已完成。


C ++标准中列出的常见序列点是什么?

这些是:

  • 在评估完整表达式的末尾(§1.9/16 )(全表达是一种表达式,不是另一个表达式的子表达。) 1

    示例:

      int a = 5; //;是这里的序列
     
  • 在评估第一个表达式之后的每个表达式(§1.9/18 )之后的评估中

    • a&& B(§5.14)
    • a || B(§5.15)
    • a? B:C(§5.16)
    • a,b(§5.18)(这里a,b是逗号运算符; in func(a,a ++) is不是逗号运算符,它仅仅是参数 a a ++ 之间的分离器。成为原始类型))
  • 在函数调用中(无论函数是否为inline),在评估所有函数参数(如果有)之后
    发生在执行功能主体中的任何表达式或语句之前(§1.9/17 )。

1:注意:全表达的评估可以包括对不是词汇的亚表达的评估
全表达的一部分。例如,在评估默认参数表达式(8.3.6)中涉及的子表达在调用函数的表达式中创建,而不是定义默认参数的

表达如第5条所述,内置运算符。当这些运算符之一在有效上下文中超载(第13条)时,因此指定了用户定义的运算符函数时,该表达式指定了功能调用,并且操作数构成了参数列表,没有它们之间的隐含序列。


什么是未定义的行为?

该标准在§1.3.12中定义了未定义的行为为

行为,例如使用错误的程序构造或错误的数据,该国际标准没有要求 3 。。

当此时,也可能会预期不确定的行为
国际标准省略了对行为的任何明确定义的描述。

3:允许的不确定行为范围从完全忽略情况以不可预测的结果忽略情况,到在翻译或程序执行过程中以有记录的方式执行环境的特征(具有或使用 -
发出诊断消息的发放),终止翻译或执行(发出诊断消息)。


未定义的行为和序列点之间有什么关系?

在我了解之前,您必须知道未定义的行为,未指定的行为和未指定的行为和行为和行为,实施定义的行为

您还必须知道,评估单个操作员的操作数和单个表达式的子表达方式,以及发生副作用的顺序,未指定

例如:

int x = 5, y = 6;

int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.

另一个示例在这里


现在§5/4 中的标准说

    1. 上一个序列和下一个序列之间的标量对象应通过评估表达式对其存储值最多修改。

这是什么意思?

非正式地,这意味着两个序列之间的变量不得多次修改。
在表达式语句中,下一个序列点通常位于终止的半隆上,上一个序列点在上一个语句的结尾处。表达式还可以包含中间序列点

从上面的句子中,以下表达式调用了不确定的行为:

i++ * ++i;   // UB, i is modified more than once btw two SPs
i = ++i;     // UB, same as above
++i = 2;     // UB, same as above
i = ++i + 1; // UB, same as above
++++++i;     // UB, parsed as (++(++(++i)))

i = (i, ++i, ++i); // UB, there's no SP between `++i` (right most) and assignment to `i` (`i` is modified more than once btw two SPs)

但是以下表达式很好:

i = (i, ++i, 1) + 1; // well defined (AFAIK)
i = (++i, i++, i);   // well defined 
int j = i;
j = (++i, i++, j*i); // well defined

    1. 此外,应访问先前的值以确定要存储的值。

这是什么意思?这意味着,如果将对象写入完整表达式中,则必须在同一表达式内对其进行任何访问,必须直接参与要编写的值的计算

例如,在 i = i + 1 中, i 的所有访问(在LHS和RHS中)直接参与了值的计算 写。所以很好。

该规则有效地将法律表达限制在访问权限之前的修改之前。

示例1:

std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2

示例2:

a[i] = i++ // or a[++i] = i or a[i++] = ++i etc

由于 i 的访问之一( a [i] )的访问之一与最终存储的值无关在i(在 i ++ 中发生的情况发生),因此没有一个好方法来定义我们的理解或编译器 - 访问是否应在存储增量值之前或之后进行。因此行为是不确定的。

示例3:

int x = i + i++ ;// Similar to above

C ++ 11 在这里< /a>。

C++98 and C++03

This answer is for the older versions of the C++ standard. The C++11 and C++14 versions of the standard do not formally contain 'sequence points'; operations are 'sequenced before' or 'unsequenced' or 'indeterminately sequenced' instead. The net effect is essentially the same, but the terminology is different.


Disclaimer : TL'DR.

Pre-requisites : An elementary knowledge of C++ Standard


What are Sequence Points?

The Standard says

At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations
shall be complete and no side effects of subsequent evaluations shall have taken place. (§1.9/7)

Side effects? What are side effects?

Evaluation of an expression produces something and if in addition there is a change in the state of the execution environment it is said that the expression (its evaluation) has some side effect(s).

For example:

int x = y++; //where y is also an int

In addition to the initialization operation the value of y gets changed due to the side effect of ++ operator.

So far so good. Moving on to sequence points. An alternation definition of seq-points given by the comp.lang.c author Steve Summit:

Sequence point is a point in time at which the dust has settled and all side effects which have been seen so far are guaranteed to be complete.


What are the common sequence points listed in the C++ Standard?

Those are:

  • at the end of the evaluation of full expression (§1.9/16) (A full-expression is an expression that is not a subexpression of another expression.)1

    Example :

    int a = 5; // ; is a sequence point here
    
  • in the evaluation of each of the following expressions after the evaluation of the first expression (§1.9/18) 2

    • a && b (§5.14)
    • a || b (§5.15)
    • a ? b : c (§5.16)
    • a , b (§5.18) (here a , b is a comma operator; in func(a,a++) , is not a comma operator, it's merely a separator between the arguments a and a++. Thus the behaviour is undefined in that case (if a is considered to be a primitive type))
  • at a function call (whether or not the function is inline), after the evaluation of all function arguments (if any) which
    takes place before execution of any expressions or statements in the function body (§1.9/17).

1 : Note : the evaluation of a full-expression can include the evaluation of subexpressions that are not lexically
part of the full-expression. For example, subexpressions involved in evaluating default argument expressions (8.3.6) are considered to be created in the expression that calls the function, not the expression that defines the default argument

2 : The operators indicated are the built-in operators, as described in clause 5. When one of these operators is overloaded (clause 13) in a valid context, thus designating a user-defined operator function, the expression designates a function invocation and the operands form an argument list, without an implied sequence point between them.


What is Undefined Behaviour?

The Standard defines Undefined Behaviour in Section §1.3.12 as

behavior, such as might arise upon use of an erroneous program construct or erroneous data, for which this International Standard imposes no requirements 3.

Undefined behavior may also be expected when this
International Standard omits the description of any explicit definition of behavior.

3 : permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or with-
out the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).


What is the relation between Undefined Behaviour and Sequence Points?

Before I get into that you must know the difference(s) between Undefined Behaviour, Unspecified Behaviour and Implementation Defined Behaviour.

You must also know that the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.

For example:

int x = 5, y = 6;

int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.

Another example here.


Now the Standard in §5/4 says

    1. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.

What does it mean?

Informally it means that between two sequence points a variable must not be modified more than once.
In an expression statement, the next sequence point is usually at the terminating semicolon, and the previous sequence point is at the end of the previous statement. An expression may also contain intermediate sequence points.

From the above sentence the following expressions invoke Undefined Behaviour:

i++ * ++i;   // UB, i is modified more than once btw two SPs
i = ++i;     // UB, same as above
++i = 2;     // UB, same as above
i = ++i + 1; // UB, same as above
++++++i;     // UB, parsed as (++(++(++i)))

i = (i, ++i, ++i); // UB, there's no SP between `++i` (right most) and assignment to `i` (`i` is modified more than once btw two SPs)

But the following expressions are fine:

i = (i, ++i, 1) + 1; // well defined (AFAIK)
i = (++i, i++, i);   // well defined 
int j = i;
j = (++i, i++, j*i); // well defined

    1. Furthermore, the prior value shall be accessed only to determine the value to be stored.

What does it mean? It means if an object is written to within a full expression, any and all accesses to it within the same expression must be directly involved in the computation of the value to be written.

For example in i = i + 1 all the access of i (in L.H.S and in R.H.S) are directly involved in computation of the value to be written. So it is fine.

This rule effectively constrains legal expressions to those in which the accesses demonstrably precede the modification.

Example 1:

std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2

Example 2:

a[i] = i++ // or a[++i] = i or a[i++] = ++i etc

is disallowed because one of the accesses of i (the one in a[i]) has nothing to do with the value which ends up being stored in i (which happens over in i++), and so there's no good way to define--either for our understanding or the compiler's--whether the access should take place before or after the incremented value is stored. So the behaviour is undefined.

Example 3 :

int x = i + i++ ;// Similar to above

Follow up answer for C++11 here.

随风而去 2025-02-19 02:45:43

这是对我的先前的答案并包含C ++ 11相关材料。


先决条件:关系的基本知识(数学)。


C ++ 11中没有序列点确实存在吗?

是!这是真的。

序列点已在和 后被测序取代()( notecorded 不确定地测序关系 C ++ 11中。


这是什么“序列”的东西是什么?

之前测序(§1.9/13)是一个关系,是:

在由单个 1

正式表示任何两个评估(请参阅下文) a a 和 b ,如果 a b 之前测序,则执行 a 应在之前执行 b 。如果 a b b 之前未进行测序,则在 a 之前未对进行测序,则 a a 代码>和 b 未续订 2

评估 a b 不确定测序的 a 是在 b 之前对进行测序时 b 是在 a 之前进行了测序,但未指定的是 3

[NOTES]

1:严格的部分顺序是 二进制关系 &lt;“ 在集合上 p ,and trastive ,即,即,即所有 a b c p 中,我们有:

........(i)。如果A&lt; b然后¬(b&lt; a)(不对称);
........(ii)。如果A&lt; B和B&lt; C然后A&lt; C(传递性)。
2:执行未序列评估可以重叠
3:不确定测序的评估不能重叠,但可以首先执行。


在C ++ 11的上下文中,“评估”一词的含义是什么?

在C ++ 11中,一般对表达式(或子表达)的评估包括:

  • 值计算(包括确定 glvalue评估并获取先前分配给对象的值/stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-lvalues-xvalues-glvalues-glvalues-and-prvalues“> prvalue评估)和

  • 副作用的启动

现在(§1.9/14)说:

在 测序的每个值计算和下一个要评估的全面表达相关的之前,都进行了测序。。。 /p>

  • 琐碎的示例:

    int x;
    x = 10;
    ++ X;

    值计算和与 ++ x 关联的副作用在值计算和 x = 10;


测序不确定的行为与上述事物之间必须有一定的关系,对吗?

是!对。

在(第1.9/15节)中,已经提到

除了注意到,对单个操作员的操作数和单个表达的子表达的评估是未序列的 4

例如:

int main()
{
     int num = 19 ;
     num = (num << 3) + (num >> 3);
} 
  1. +运算符的操作数的评估相对于彼此而言是未序列的。
  2. 评估&lt;&lt; &gt;&gt; 运营商相对于彼此而言是未序列的。

4:在执行过程中多次评估的表达式中
在一个程序中,在不同的评估中不必始终如一地执行程序, 未确定对其子表达的评估不必始终如一地进行。

(§1.9/15)
操作数的价值计算
在运算符的结果计算之前对操作员进行测序。

这意味着在 x + y x y 的值计算之前,请在(x + y)<的值计算之前进行测序。 /代码>。

更重要的是

(§1.9/15)如果相对于

,对标量对象的副作用是未序列的

(a)对同一标量对象的另一种副作用

(b)使用同一标量对象的值计算值。

行为是不确定的

示例:

int i = 5, v[10] = { };
void  f(int,  int);
  1. i = i ++ * ++ i; //未定义的行为
  2. i = ++ i+i ++; //未定义的行为
  3. i = ++ i +++ i; //未定义的行为
  4. i = v [i ++]; //未定义的行为
  5. i = v [++ i]://确定的行为
  6. i = i +++1; //未定义的行为
  7. i = ++ i +1; //定义良好的行为
  8. ++++ i; //定义良好的行为
  9. f(i = -1,i = -1); //未定义的行为(见下文)

调用函数(无论该函数是否为inline)时,在执行每个表达式指定函数的后缀表达式相关的每个值计算和副作用,然后在执行每个表达式或语句中的每个表达式中进行测序所谓功能的主体。 [注意: 价值计算和与不同参数表达式相关的副作用是未序列的。 - end Note ]

表达式(5),(7)和(8)不调用未定义的行为。查看以下答案以进行更详细的说明。


/ /strong>:

如果您在帖子中发现任何缺陷,请发表评论。权力用户(使用REP&GT; 20000)请随时编辑帖子,以纠正错别字和其他错误。

This is a follow up to my previous answer and contains C++11 related material..


Pre-requisites : An elementary knowledge of Relations (Mathematics).


Is it true that there are no Sequence Points in C++11?

Yes! This is very true.

Sequence Points have been replaced by Sequenced Before and Sequenced After (and Unsequenced and Indeterminately Sequenced) relations in C++11.


What exactly is this 'Sequenced before' thing?

Sequenced Before(§1.9/13) is a relation which is:

between evaluations executed by a single thread and induces a strict partial order1

Formally it means given any two evaluations(See below) A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced 2.

Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which3.

[NOTES]

1 : A strict partial order is a binary relation "<" over a set P which is asymmetric, and transitive, i.e., for all a, b, and c in P, we have that:

........(i). if a < b then ¬ (b < a) (asymmetry);
........(ii). if a < b and b < c then a < c (transitivity).
2 : The execution of unsequenced evaluations can overlap.
3 : Indeterminately sequenced evaluations cannot overlap, but either could be executed first.


What is the meaning of the word 'evaluation' in context of C++11?

In C++11, evaluation of an expression (or a sub-expression) in general includes:

  • value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and

  • initiation of side effects.

Now (§1.9/14) says:

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

  • Trivial example:

    int x;
    x = 10;
    ++x;

    Value computation and side effect associated with ++x is sequenced after the value computation and side effect of x = 10;


So there must be some relation between Undefined Behaviour and the above-mentioned things, right?

Yes! Right.

In (§1.9/15) it has been mentioned that

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced4.

For example :

int main()
{
     int num = 19 ;
     num = (num << 3) + (num >> 3);
} 
  1. Evaluation of operands of + operator are unsequenced relative to each other.
  2. Evaluation of operands of << and >> operators are unsequenced relative to each other.

4: 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.

(§1.9/15)
The value computations of the operands of an
operator are sequenced before the value computation of the result of the operator.

That means in x + y the value computation of x and y are sequenced before the value computation of (x + y).

More importantly

(§1.9/15) If a side effect on a scalar object is unsequenced relative to either

(a) another side effect on the same scalar object

or

(b) a value computation using the value of the same scalar object.

the behaviour is undefined.

Examples:

int i = 5, v[10] = { };
void  f(int,  int);
  1. i = i++ * ++i; // Undefined Behaviour
  2. i = ++i + i++; // Undefined Behaviour
  3. i = ++i + ++i; // Undefined Behaviour
  4. i = v[i++]; // Undefined Behaviour
  5. i = v[++i]: // Well-defined Behavior
  6. i = i++ + 1; // Undefined Behaviour
  7. i = ++i + 1; // Well-defined Behaviour
  8. ++++i; // Well-defined Behaviour
  9. f(i = -1, i = -1); // Undefined Behaviour (see below)

When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. [Note: Value computations and side effects associated with different argument expressions are unsequenced. — end note]

Expressions (5), (7) and (8) do not invoke undefined behaviour. Check out the following answers for a more detailed explanation.


Final Note :

If you find any flaw in the post please leave a comment. Power-users (With rep >20000) please do not hesitate to edit the post for correcting typos and other mistakes.

风和你 2025-02-19 02:45:43

c ++ 17 n4659 )包括一个建议惯用性C ++的精炼表达评估顺序
这定义了更严格的表达评估顺序。

特别是 句子

8.18分配和复合分配操作员
....

在所有情况下,分配都在值之后进行测序
左右操作数的计算,以及在分配表达式的价值计算之前。
在左操作数之前对右操作数进行了测序。

以及以下澄清

表达式 x 被认为是在表达式 y 之前测序的
在每个值之前对表达式 x 关联的每个副作用进行测序
与表达式 y

相关的计算和每个副作用

使几种先前未定义的行为有效,包括所讨论的行为:

a[++i] = i;

但是其他几个类似的案例仍然导致不确定的行为。

N4140 中:

i = i++ + 1; // the behavior is undefined

但是在 N4659

i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined

,当然,使用C ++ 17的编译器并不一定意味着人们应该开始编写此类表达式。

C++17 (N4659) includes a proposal Refining Expression Evaluation Order for Idiomatic C++
which defines a stricter order of expression evaluation.

In particular, the following sentence

8.18 Assignment and compound assignment operators:
....

In all cases, the assignment is sequenced after the value
computation of the right and left operands, and before the value computation of the assignment expression.
The right operand is sequenced before the left operand.

together with the following clarification

An expression X is said to be sequenced before an expression Y if every
value computation and every side effect associated with the expression X is sequenced before every value
computation and every side effect associated with the expression Y.

make several cases of previously undefined behavior valid, including the one in question:

a[++i] = i;

However several other similar cases still lead to undefined behavior.

In N4140:

i = i++ + 1; // the behavior is undefined

But in N4659

i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined

Of course, using a C++17 compliant compiler does not necessarily mean that one should start writing such expressions.

老子叫无熙 2025-02-19 02:45:43

我猜想发生了这种变化的根本原因,不仅要使旧的解释更加清晰:原因是并发。未指定的阐述顺序仅选择了几个可能的串行顺序之一,这与订购前后完全不同,因为如果没有指定的订单,则可以进行并发评估:与旧规则相关。例如:

f (a,b)

以前是A当时的B,或者B然后B。现在,A和B可以通过交织甚至在不同核心上进行的指令进行评估。

I am guessing there is a fundamental reason for the change, it isn't merely cosmetic to make the old interpretation clearer: that reason is concurrency. Unspecified order of elaboration is merely selection of one of several possible serial orderings, this is quite different to before and after orderings, because if there is no specified ordering, concurrent evaluation is possible: not so with the old rules. For example in:

f (a,b)

previously either a then b, or, b then a. Now, a and b can be evaluated with instructions interleaved or even on different cores.

游魂 2025-02-19 02:45:43

C99(ISO/IEC 9899:TC3)中,该讨论中似乎没有关于evaluaiton的顺序进行以下结局。

[...]子表达的评估顺序和其中的顺序
副作用都未指定。 (第6.5页67)

未指定操作数的评估顺序。如果尝试
为了修改任务运营商的结果或访问它
在下一个序列点之后,行为[SIC]不确定。(部分
6.5.16 pp 91)

In C99(ISO/IEC 9899:TC3) which seems absent from this discussion thus far the following steteents are made regarding order of evaluaiton.

[...]the order of evaluation of subexpressions and the order in which
side effects take place are both unspecified. (Section 6.5 pp 67)

The order of evaluation of the operands is unspecified. If an attempt
is made to modify the result of an assignment operator or to access it
after the next sequence point, the behavior[sic] is undefined.(Section
6.5.16 pp 91)

天气好吗我好吗 2025-02-19 02:45:43

该标准指定仅当任何定义程序的行为不明显影响的行为时,才可以执行优化变换。序列点规则的编写是为了允许以不跨序列点的方式重新排序动作,即使可以观察到这种重新排序的效果,也可以通过将不确定的行为归类为任何动作,任何使得能够影响效果的动作可以观察到允许的转换。

不幸的是,这种规则制作方法的结果是,即使在没有关系的情况下,也必须明确地强制采取行动的测序。例如,Java可以在不使用任何内存屏障的情况下缓存字符串的哈希代码;缺乏内存屏障可能会导致线程感知哈希代码没有缓存,即使在另一个线程实际缓存之后,也可以执行冗余的哈希值计算,但是偶尔的额外计算的成本通常会大大显着。低于在每个访问中添加内存障碍的成本。但是,在C中,试图读取缓存的哈希代码字段,而另一个线程正在修改它将产生不确定的行为,即使在平台上,读取尝试的唯一可能效果将是产生旧值(表明哈希代码是' t缓存)或写的最后一个值(这始终是正确的哈希代码)。

The Standard specifies that optimizing transforms may be performed if any only if they do not observably affect the behavior of any defined program. The sequence-point rules are written to allow reordering of actions in ways that don't cross sequence points, even if the effects of such reordering might be observable, by classifying as Undefined Behavior any actions that would make it possible for the effects of an allowable transformation to be observed.

An unfortunate consequence of this approach to rule making is that it makes it necessary for programs to explicitly force the sequencing of actions even in cases where it wouldn't matter. For example, Java can cache strings' hash codes without using any memory barriers; the lack of memory barriers may cause a thread to perceive that the hash code isn't cached, even after another thread has actually cached it, and thus perform a redundant hash value computation, but the cost of the occasional extra calculations will generally be significantly below the cost of adding a memory barrier on every access. In C, however, attempting to read the cached hash code field while another thread is modifying it would yield Undefine Behavior, even on platforms where the only possible effects of the read attempt would be to yield the old value (indicating the hash code wasn't cached) or the last value written (which would always be the correct hash code).

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