IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言中的序列点(sequence point)和副作用(side effects) -> 正文阅读

[C++知识库]C语言中的序列点(sequence point)和副作用(side effects)

目录

1. 副作用(side effect)

2.??序列点(sequence point)

遵循原则:


?了解序列点之前先来看下副作用:

1. 副作用(side effect)

看下边代码:

int factorial(int n)
{
    int result = 1;
    int i;
    for(i = 1; i <= n; ++i)
    result = result * i;
    return result;
}

?其中++i这个表达式相当于i = i + 1[9],++称为前缀自增运算符(Prefix Increment Operator),
类似地,--称为前缀自减运算符(Prefix Decrement Operator)[10],--i相当于i = i - 1。如果
把++i这个表达式看作一个函数调用,除了传入一个参数返回一个值(等于参数值加1)之外,还产
生一个Side Effect,就是把变量i的值增加了1。
++和--运算符也可以用在变量后面,例如i++和i--,为了和前缀运算符区别,这两个运算符称为后
缀自增运算符(Postfix Increment Operator)和后缀自减运算符(Postfix Decrement
Operator)。如果把i++这个表达式看作一个函数调用,传入一个参数返回一个值,返回值就等于
参数值(而不是参数值加1),此外也产生一个Side Effect,就是把变量i的值增加了1,它和++i的
区别就在于返回值不同。同理,--i返回减1之后的值,而i--返回减1之前的值,但这两个表达式都
产生同样的Side Effect,就是把变量i的值减了1。

2.??序列点(sequence point)

int main(void)
{
	int a = 2, b = 3, c;
	//a = a++;
	//c = a+++++a;  //error
	c = a++ + ++a;  // 2+4 or 3+3 ?
	
	printf("a:%d b:%d c:%d\n", a, b, c); 
	printf("a:%d a++:%d\n", a, a++); 
	printf("b:%d ++b:%d\n", b, ++b); 
	printf("c:%d c++:%d ++c:%d\n", c, c++, ++c);
	printf("c:%d ++c:%d c++:%d\n", c, ++c, c++);	
	
	return 0;
}

加上gcc 加上-Wall编译:

?

执行结果(注意这个结果跟编译器相关):

?

各种Sequence Point?

1、调用一个函数时,在所有准备工作做完之后、函数调用开始之前是Sequence Point。比如调
用foo(f(), g())时,foo、f()、g()这三个表达式哪个先求值哪个后求值是Unspecified,但是必须
都求值完了才能做最后的函数调用,所以f()和g()的Side Effect按什么顺序发生不一定,但必定在
这些Side Effect全部作用完之后才开始调用foo函数。
2、条件运算符?:、逗号运算符、逻辑与&&、逻辑或||的第一个操作数求值之后是Sequence
Point。我们刚讲过条件运算符和逗号运算符,条件运算符要根据表达式1的值是否为真决定下一步
求表达式2还是表达式3的值,如果决定求表达式2的值,表达式3就不会被求值了,反之也一样,逗
号运算符也是这样,表达式1求值结束才继续求表达式2的值。?
?? ?&&运算与此类似,a && b的计算过程是:首先求表达式a的值,如果a的值是假则整个表达式的值
是假,不会再去求b的值;如果a的值是真,则下一步求b的值作为整个表达式的值。所以,a &&
b相当于“if a then b”,而a || b相当于“if not a then b”。这种特性称为Short-circuit,很多人喜欢利
用Short-circuit特性简化代码。
3、在一个完整的声明末尾是Sequence Point,所谓完整的声明是指这个声明不是另外一个声明的
一部分。比如声明int a[10], b[20];,在a[10]末尾是Sequence Point,在b[20]末尾也是。
4、在一个完整的表达式末尾是Sequence Point,所谓完整的表达式是指这个表达式不是另外一个
表达式的一部分。所以如果有f(); g();这样两条语句,f()和g()是两个完整的表达式,f()的Side
Effect必定在g()之前发生。
5、在库函数即将返回时是Sequence Point。这条规则似乎可以包含在上一条规则里面,因为函数
返回时必然会结束掉一个完整的表达式。而事实上很多库函数是以宏定义的形式实现的(第 2.1 节
“函数式宏定义”),并不是真正的函数,所以才需要有这条规则。
还有两种Sequence Point和某些C标准库函数的执行过程相关,此处从略,有兴趣的读者可参
考[C99]的Annex C。

3. 遵循原则:

写表达式应遵循的原则一:在两个Sequence Point之间,同一个变量的值只允许被改变一次。仅
有这一条原则还不够,例如a[i++] = i;的变量i只改变了一次,但结果仍是Undefined,因为等号
左边改i的值,等号右边读i的值,到底是先改还是先读?这个读写顺序是不确定的。但为什么i =
i + 1;就没有歧义呢?虽然也是等号左边改i的值,等号右边读i的值,但你不读出i的值就没法计
算i + 1,那拿什么去改i的值呢?所以这个读写顺序是确定的。写表达式应遵循的原则二:如果在
两个Sequence Point之间既要读一个变量的值又要改它的值,只有在读写顺序确定的情况下才可
以这么写。

另外可参考:

https://blog.csdn.net/tsroad/article/details/49834261

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-10 13:14:33  更:2021-08-10 13:16:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 20:10:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码