解决c/c++的sequence points和side effects问题

2023-05-16

在看一篇文章时,提到这样一段代码

#include <stdio.h>
void foo(void)
{
int a = 41;
a = a++;
printf("%d\n", a);
}
int main(void)
{
foo();
}

本以为很简单嘛,就是不要忘了a赋值之后还要自己。其实是自己想的太简单了。
因为在vs2008和linux gcc下跑的结果不一样。研究一下这里面的原因。
在vs2008下,输出的是42.但是在linux gcc 下
这里写图片描述
这里写图片描述
结果居然是41.
那篇文章解释说
The rules for sequencing says
that you can only update a variable once
between sequence points. Here you try to
update it two times, and this causes a to
become undefined.
于是看看sequence points问题
在msdn中这样讲的
Between consecutive “sequence points” an object’s value can be modified only once by an expression.
就是在序列点之间,对象只能被修改一次。
还有一个概念就是side effects

下面是一篇博客上写的


C 语言中副作用(side effect):是指对数据对象或者文件的修改。例如,语句 var = 99; 的副作用是把 var 的值修改成 99。对表达式求值也可能产生副作用,例如,对表达式求se = 100;
求值所产生的副作用就是 se 的值被修改成 100。

序列点(sequence point):是指程序运行中的一个特殊的时间点,在该点之前的所有副作用已经结束,并且后续的副作用还没发生。C 语句结束标志——分号(;)是序列点。标准规定,在两个序列点之间,一个对象所保存的值最多只能被修改一次。

C 语句中由赋值、自增或者自减等引起的副作用在分号之前必须结束。我们以后会说到一些包含序列点的运算符。任何完整表达式(full expression)运算结束的那个时间点也是序列点。所谓完整表达式,就是说这个表达式不是子表达式。而所谓的子表达式,则是指表达式中的表达式。例如:f = ++e % 3 这整个表达式就是一个完整表达式。这个表达式中的 ++e、3 和 ++e % 3 都是它的子表达式。

有了序列点的概念,我们下面来分析一下一个很常见的错误:
int x = 1, y;
y = x++ + x++;
这里 y = x++ + x++ 是完整表达式,而 x++ 是它的子表达式。这个完整表达式运算结束的那一点是一个序列点,int x = 1, y; 中的 ; 也是一个序列点。也就是说,x++ + x++ 位于两个序列点之间。标准规定,在两个序列点之间,一个对象所保存的值最多只能被修改一次。但是我们清楚可以看到,上面这个例子中,x 的值在两个序列点之间被修改了两次。这显然是错误的!这段代码在不同的编译器上编译可能会导致 y 的值有所不同。比较常见的结果是 y 的值最后被修改为 2 或者 3。在此,我不打算就这个问题作更深入的分析,各位只要记住这是错误的,别这么用就可以了。有兴趣的话,可以看看以下列出的相关资料。

C 语言标准对副作用和序列点的定义如下:
Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. 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. The point of calling a function, after evaluating its arguments.
2. The end of the first operand of the && operator.
3. The end of the first operand of the || operator.
4. The end of the first operand of the ?: conditional operator.
5. The end of the each operand of the comma operator.
6. Completing the evaluation of a full expression. They are the following:
7. Evaluating the initializer of an auto object.
8. The expression in an ‘ordinary’ statement—an expression followed by semicolon.
9. The controlling expressions in do , while , if , switch or for statements.
10. The other two expressions in a for statement.
11. The expression in a return statement.
编译时可以加上“-Wsequence-point ”让编译器帮我们检查可能的关于检查点的错误。

/*
* test_sequence_point.c
* gcc -Wsequence-point test_sequence_point.c
*/
#i nclude
int main() {
         int      i = 12;
         i = i--;
         printf("the i is %d/n", i);
         return 0;
}
gcc -Wsequence-point test_sequence_point.c
test_sequence_point.c: In function `main':
test_sequence_point.c:10: warning: operation on `i' may be undefined
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决c/c++的sequence points和side effects问题 的相关文章

  • 如何从 F# Seq 获取连续值对

    我有一个序列 1 a 2 b 3 c 我怎样才能把这个seq变成 1 a 2 b 3 c 这是一个非常聪明的解决方案 let s 1 a 2 b 3 c let pairs s s gt Seq pairwise gt Seq mapi f
  • 从序列创建关系矩阵 (Matlab)

    我有一个序列 S S ABCD which means A
  • 从具有开始/结束日期的行创建年份序列行的数据框

    我对 R 和编码来说是一个相对较新的用户 我已经搜索过但无法解决这个问题 我有以下数据 groupid start date end date Status 1 2014 01 01 2017 01 01 A 1 2018 01 01 20
  • Int64 创建数字范围

    我需要能够创建顺序长度超过 19 位的数字范围 我尝试使用 Enumerable Range 120000003463014 50000 ToList 这适用于较小的数字 但使用上面的代码时 我收到一条错误消息 指出它对于 int32 数字
  • jQuery 图片库非功能性淡入淡出效果

    这是一个简单的图像库脚本 用于淡入和淡出带有背景图像的 div 它很慢而且不能正常工作 看起来所有图像都一起出现和消失 没有任何动画 该画廊应该将每张图像淡出到下一张图像中 function gallery timerp window se
  • “fasta 文件中序列的平均长度”:你能改进这个 Erlang 代码吗?

    我正在尝试获取平均长度快速序列 http en wikipedia org wiki Fasta Sequence using Erlang fasta 文件看起来像这样 gt title1 ATGACTAGCTAGCAGCGATCGACC
  • MySQL:基于另一个字段添加序列列

    我正在处理一些遗留代码 数据库 并且需要向数据库添加一个字段 该字段将记录与该 外国 id 相关的序列号 示例表数据 当前 ID ACCOUNT some other stuff 1 1 2 1 3 1 4 2 5 2 6 1 我需要添加一
  • 使用 dplyr 和 rle 对条件组中的连续值进行计数

    我的问题与下面提出的问题非常相似 但是我想添加一个附加命令以仅返回序列具有超过 2 个连续值的情况 当给定的序列运行在给定的时代和给定的年份内有超过 2 个连续的数字时 如何计算连续 成功 的数量 即 consec 中的 1 个 类似的问题
  • 可以在 Oracle 的 SELECT 中执行自动编号序列吗?

    我需要在 Oracle 中完成一项任务 但我不知道如何才能做到这一点 好的 当我动态定义自动编号序列时 我需要执行 SELECT 例如 Select autonumber 1 9000 as auto from some table 结果是
  • 如何修改 Kotlin 序列的前缀但保留尾部?

    Kotlin 提供take and takeWhile先采取的方法n的项目Sequence
  • XSLT 中的序列

    我的 xml 输入是
  • Win 10 Excel 2016 无法解释的 PixelsToPoints 系数来定位用户窗体

    序言 当尝试将用户窗体定位在特定像素位置 存储在POINTAPI类型结构 必须将 Pixel 坐标转换为 Point 坐标才能设置UserForm Left and UserForm TopVBA 属性 我们称这个系数为K 从我的测试中 我
  • 如何使用 set 维护列表的顺序?

    In 1 l1 a 2 3 0 9 0 0 2 6 b a In 2 l2 list set l1 In 3 l2 Out 3 a 0 2 3 6 9 0 b 在这里您可以看到列表 l2 的顺序与原始 l1 的顺序不同 我需要从列表中删除重
  • C++11 的序列压缩函数?

    使用新的基于范围的 for 循环 我们可以编写如下代码 for auto x Y IMO 是哪个huge改进自 例如 for std vector
  • SQL Server - 实现序列

    我有一个系统 要求我在数据进入数据库之前拥有数据的 ID 我正在使用 GUID 但发现它们太大而无法证明其便利性 我现在正在尝试实现一个序列生成器 它基本上为给定的上下文保留一系列唯一的 ID 值 代码如下 ALTER PROCEDURE
  • Hibernate JPA 序列(非 Id)

    是否可以对某些列使用数据库序列不是标识符 不是复合标识符的一部分 我使用 hibernate 作为 jpa 提供程序 并且我有一个表 其中有一些生成值的列 使用序列 尽管它们不是标识符的一部分 我想要的是使用序列为实体创建新值 其中序列的列
  • 递归地添加数字序列

    嘿 我想用一些递归来刷新我的想法 我想添加从 开始 到 结束 含 的所有数字 即如果开始是 1 结束是 5 那么答案就是 1 2 3 4 5 15 到目前为止我已经得到了这个 int calc int start int end if st
  • 点列表的 3D 轮廓(凹壳)

    我有一个 C 中的 Vector3 点列表 我需要计算这些点的凹轮廓 确实有很多参考资料 特别是对于 凸 分辨率 由于格雷厄姆算法 我已经成功实现了 然而 由于我现在需要有效地计算凹轮廓 所以我迷失了 维基百科确实列出了很多用于凸计算的资源
  • 与两点相交的圆心

    给定 2D 平面上的两个点 以及与这两个点相交的半径为 r 的圆 计算该圆中心的公式是什么 我意识到圆圈可以放置在两个地方 当从任意角度开始扫描围绕其中一个点连接两个点的线时 我希望首先沿顺时针方向遇到其中心的圆 我想这是我的问题的下一阶段
  • 两组点之间的最佳匹配

    I ve got two lists of points let s call them L1 P1 x1 y1 Pn xn yn and L2 P 1 x 1 y 1 P n x n y n 我的任务是找到它们点之间的最佳匹配 以最小化它

随机推荐