简体   繁体   English

C和C ++与序列点和UB的差异

[英]Differences in C and C++ with sequence points and UB

I used this post Undefined Behavior and Sequence Points to document undefined behavior( UB ) in a C program and it was pointed to me that C and C++ have their own divergent rules for this [sequence points] . 我使用这篇文章未定义的行为和序列点来记录C程序中的未定义行为( UB ),并且我指出C and C++ have their own divergent rules for this [sequence points] So what are the differences between C and C++ when it comes to sequence points and related UB ? 那么当涉及到序列点和相关的UB时, CC ++之间有什么区别? Can't I use a post about C++ sequences to analyze what is happening in C code? 我不能使用关于C ++序列的帖子来分析C代码中发生的事情吗?

* Of Course I am not talking about features of C++ not applicable to C . *当然我不是在谈论不适用于CC++特性。

There are two parts to this question, we can tackle a comparison of sequence points rules without much trouble. 这个问题有两个部分,我们可以毫不费力地解决序列点规则的比较。 This does not get us too far though, C and C++ are different languages which have different standards( the latest C++ standard is almost twice as large as the the latest C standard ) and even though C++ uses C as a normative reference it would be incorrect to quote the C++ standard for C and vice versa, regardless how similar certain sections may be. 这并不让我们虽然太远,C和C ++是具有不同标准的不同的语言( 最新的C ++标准几乎是两倍于中大最新的C标准 ),而且即使C ++使用C作为规范性引用这将是不正确引用C的C ++标准,反之亦然,无论某些部分有多相似。 The C++ standard does explicitly reference the C standard but that is for small sections. C ++标准确实引用了C标准,但这适用于小部分。

The second part is a comparison of undefined behavior between C and C++, there can be some big differences and enumerating all the differences in undefined behavior may not be possible but we can give some indicative examples. 第二部分是C和C ++之间未定义行为的比较,可能存在一些重大差异,并且枚举未定义行为中的所有差异可能是不可能的,但我们可以给出一些指示性示例。

Sequence Points 序列点

Since we are talking about sequence points then this is covering pre C++11 and pre C11. 由于我们讨论的是序列点,所以这涵盖了C ++ 11之前和C11之前的版本。 The sequence point rules do not differ greatly as far as I can tell between C99 and Pre C++11 draft standards. 就C99和Pre C ++ 11草案标准而言,序列点规则没有太大差别。 As we will see in some of the example I give of differing undefined behavior the sequence point rules do not play a part in them. 正如我们将在一些示例中看到的,我给出了不同的未定义行为,序列点规则不会在其中起作用。

The sequence points rules are covered in the closest draft C++ standard to C++03 section 1.9 Program execution which says: 序列点规则包含在C ++ 031.9最接近的草案C ++标准中。 程序执行说:

  • There is a sequence point at the completion of evaluation of each full-expression 12) . 在完成每个完整表达式12)的评估时存在序列点。
  • When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all function arguments (if any) which takes place before execution of any expressions or statements in the function body. 在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有)之后,都会有一个序列点。
  • There is also a sequence point after the copying of a returned value and before the execution of any expressions outside the function 13) . 在复制返回值之后和执行函数13)之外的任何表达式之前,还有一个序列点。 Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. C ++中的几个上下文导致对函数调用的评估,即使在翻译单元中没有出现相应的函数调用语法。 [ Example: evaluation of a new expression invokes one or more allocation and constructor functions; [示例:对新表达式的求值调用一个或多个分配和构造函数; see 5.3.4. 见5.3.4。 For another example, invocation of a conversion function (12.3.2) can arise in contexts in which no function call syntax appears. 另一个例子,转换函数(12.3.2)的调用可能出现在没有出现函数调用语法的上下文中。 —end example ] 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. -end example]函数入口和函数出口的序列点(如上所述)是被评估的函数调用的特征,无论调用函数的表达式的语法如何。
  • In the evaluation of each of the expressions 在评估每个表达式时

     a && b a || b a ? b : c a , b 

    using the built-in meaning of the operators in these expressions (5.14, 5.15, 5.16, 5.18), there is a sequence point after the evaluation of the first expression14). 使用这些表达式(5.14,5.15,5.16,5.18)中的运算符的内置含义,在评估第一个表达式14)之后有一个序列点。

I will use the sequence point list from the draft C99 standard Annex C which although it is not normative I can find no disagreement with the normative sections it references. 我将使用C99标准Annex C草案中的序列点列表,虽然它不是规范性的,但我发现它与它所引用的规范性部分没有异议。 It says: 它说:

The following are the sequence points described in 5.1.2.3: 以下是5.1.2.3中描述的序列点:

  • The call to a function, after the arguments have been evaluated (6.5.2.2). 在评估参数之后调用函数(6.5.2.2)。
  • The end of the first operand of the following operators: logical AND && (6.5.13); 以下运算符的第一个操作数的结尾:logical AND &&(6.5.13); logical OR || 逻辑OR || (6.5.14); (6.5.14); conditional ? 条件? (6.5.15); (6.5.15); comma , (6.5.17). 逗号,(6.5.17)。
  • The end of a full declarator: declarators (6.7.5); 完整声明者的结尾:声明者(6.7.5);
  • The end of a full expression: an initializer (6.7.8); 完整表达式的结束:初始化器(6.7.8); the expression in an expression statement (6.8.3); 表达式中的表达式(6.8.3); the controlling expression of a selection statement (if or switch) (6.8.4); 选择语句的控制表达式(if或switch)(6.8.4); the controlling expression of a while or do statement (6.8.5); while或do语句的控制表达式(6.8.5); each of the expressions of a for statement (6.8.5.3); for语句的每个表达式(6.8.5.3); the expression in a return statement (6.8.6.4). 返回语句中的表达式(6.8.6.4)。

The following entries do not seem to have equivalents in the draft C++ standard but these come from the C standard library which C++ incorporates by reference: 以下条目似乎没有C ++标准草案中的等价物,但它们来自C标准库,C ++通过引用合并:

  • Immediately before a library function returns (7.1.4). 在库函数返回之前(7.1.4)。
  • After the actions associated with each formatted input/output function conversion specifier (7.19.6, 7.24.2). 在与每个格式化的输入/输出函数转换说明符(7.19.6,7.24.2)相关联的操作之后。
  • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call (7.20.5). 紧接在每次调用比较函数之前和之后,以及对比较函数的任何调用和作为参数传递给该调用的对象的任何移动之间(7.20.5)。

So there is not much of a difference between C and C++ here. 所以C和C ++之间没有太大的区别。

Undefined Behavior 未定义的行为

When it comes to the typical examples of sequence points and undefined behavior, for example those covered in Section 5 Expression dealing with modifying a variable more than once within a sequence points I can not come up with an example that is undefined in one but not the other. 当涉及到序列点和未定义行为的典型示例时,例如第5节中涉及在序列点中多次修改变量的表达式 ,我无法想出一个未定义的示例,但不是其他。 In C99 it says: 在C99中它说:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. 在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次。 72) Furthermore, the prior value shall be read only to determine the value to be stored. 72)此外,先前值应只读以确定要存储的值。 73) 73)

and it provides these examples: 它提供了以下示例:

i = ++i + 1;
a[i++] = i;

and in C++ it says: 在C ++中它说:

Except where noted, 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.57) 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. 除非另有说明,否则单个运算符的操作数和各个表达式的子表达式的评估顺序以及副作用发生的顺序是未指定的.57)在前一个和下一个序列点之间,标量对象应该修改其存储值最多一次通过表达式的评价。 Furthermore, the prior value shall be accessed only to determine the value to be stored. 此外,只能访问先前值以确定要存储的值。 The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; 对于完整表达式的子表达式的每个允许排序,应满足本段的要求; otherwise the behavior is undefined 否则行为未定义

and provides these examples: 并提供以下示例:

i = v[i ++]; / / the behavior is undefined
i = ++ i + 1; / / the behavior is undefined

In C++11 and C11 we do have one major difference which is covered in Assignment operator sequencing in C11 expressions which is the following: 在C ++ 11和C11中,我们确实有一个主要的区别,这在C11表达式中的赋值运算符排序中有所涉及,如下所示:

i = ++i + 1;

This is due to the result of pre-increment being an lvalue in C++11 but not in C11 even though the sequencing rules are the same. 这是因为即使排序规则相同,预增量在C ++ 11中也是左值 ,但在C11中不是。

We do have major difference in areas that have nothing to do with sequence points: 我们在与序列点无关的区域确实存在重大差异:

There are probably plenty more examples but these are ones I have written about before. 可能有更多的例子,但这些是我之前写过的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM