我使用这篇文章Undefined Behavior and Sequence Points来记录C程序中的未定义行为(UB),它指向我。那么在序列点和相关的UB方面, C和C++之间有什么区别?我不能用一篇关于C++序列的帖子来分析C代码中发生的事情吗?C and C++ have their own divergent rules for this [sequence points]
* 当然我不是在谈论C++
不适用于C
.
我使用这篇文章Undefined Behavior and Sequence Points来记录C程序中的未定义行为(UB),它指向我。那么在序列点和相关的UB方面, C和C++之间有什么区别?我不能用一篇关于C++序列的帖子来分析C代码中发生的事情吗?C and C++ have their own divergent rules for this [sequence points]
* 当然我不是在谈论C++
不适用于C
.
这个问题有两个部分,我们可以毫不费力地解决序列点规则的比较。这并没有让我们走得太远,C 和 C++ 是不同的语言,具有不同的标准(最新的 C++ 标准几乎是最新C 标准的两倍),即使 C++ 使用 C 作为规范性参考,它也是不正确的引用 C 的 C++ 标准,反之亦然,无论某些部分有多么相似。C++ 标准确实明确引用了 C 标准,但这是针对小部分的。
第二部分是C 和 C++ 之间未定义行为的比较,可能存在一些很大的差异,列举未定义行为的所有差异可能是不可能的,但我们可以给出一些指示性示例。
序列点
由于我们谈论的是序列点,所以这涵盖了 pre C++11 和 pre C11。据我所知,C99 和 Pre C++11 草案标准之间的序列点规则差别不大。正如我们将在我给出的不同未定义行为的一些示例中看到的那样,序列点规则在其中不起作用。
序列点规则包含在最接近 C++03部分1.9
程序执行的 C++ 标准草案中,其中说:
在每个表达式的评估中
a && b
a || b
a ? b : c
a , b
使用这些表达式(5.14、5.15、5.16、5.18)中运算符的内置含义,在第一个表达式求值之后有一个序列点 14)。
我将使用 C99 标准草案中的序列点列表Annex C
,尽管它不是规范的,但我无法发现它与它引用的规范部分存在分歧。它说:
以下是5.1.2.3中描述的顺序点:
以下条目似乎在 C++ 标准草案中没有等效项,但这些条目来自 C++ 通过引用合并的 C 标准库:
因此,这里的 C 和 C++ 之间没有太大区别。
未定义的行为
当涉及到序列点和未定义行为的典型示例时,例如在处理在序列点内多次修改变量的部分5
表达式中所涵盖的那些,我无法想出一个在一个中未定义但在另一个中未定义的示例. 在 C99 中它说:
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。72)此外,应仅读取先验值以确定要存储的值。73)
它提供了以下示例:
i = ++i + 1;
a[i++] = i;
在 C++ 中它说:
除非另有说明,单个运算符的操作数和单个表达式的子表达式的求值顺序以及副作用发生的顺序是未指定的。57) 在前一个和下一个序列点之间,标量对象应修改其存储值最多一次通过表达式的评估。此外,只能访问先验值以确定要存储的值。对于完整表达式的子表达式的每个允许排序,都应满足本段的要求;否则行为未定义
并提供以下示例:
i = v[i ++]; / / the behavior is undefined
i = ++ i + 1; / / the behavior is undefined
在 C++11 和 C11 中,我们确实有一个主要区别,这在 C11 表达式中的赋值运算符排序中有所介绍,如下所示:
i = ++i + 1;
这是由于预增量的结果在 C++11 中是左值,但在 C11 中不是,即使排序规则相同。
我们在与序列点无关的领域确实存在重大差异:
可能还有更多的例子,但这些是我之前写过的。