[转载]C++的顺序点(sequence point)和副作用(side effect)
有关i=(++i)+(i++)这种东西的深入解释,不仅仅是简单粗暴undefined behavior。
====
一.副作用(side effect)
表达式有两种功能:每个表达式都产生一个值( value ),同时可能包含副作用( side effect )。副作用是指改变了某些变量的值。
如:
1:20 //这个表达式的值是20;它没有副作用,因为它没有改变任何变量的值。
2:x=5 // 这个表达式的值是5;它有一个副作用,因为它改变了变量x的值。
3:x=y++ // 这个表达示有两个副作用,因为改变了两个变量的值。
4:x=x++ // 这个表达式也有两个副作用,因为变量x的值发生了两次改变。
二.求值顺序点
表达式求值规则的核心在于 顺序点( sequence point ) [ C99 6.5 Expressions 条款2 ] [ C++03 5 Expressions 概述 条款4 ]。
顺序点的意思是在一系列步骤中的一个“结算”的点,语言要求这一时刻的求值和副作用全部完成,才能进入下面的部分。在C/C++中只有以下几种存在顺序点:
1)分号;
2)未重载的逗号运算符的左操作数赋值之后(即','处)
3)未重载的'||'运算符的左操作数赋值之后(即'||'处);
4)未重载的'&&'运算符的左操作数赋值之后(即"&&"处);
5)三元运算符'? : '的左操作数赋值之后(即'?'处);
6)在函数所有参数赋值之后但在函数第一条语句执行之前;
7)在函数返回值已拷贝给调用者之后但在该函数之外的代码执行之前;
8)每个基类和成员初始化之后;
9)在每一个完整的变量声明处有一个顺序点,例如int i, j;中逗号和分号处分别有一个顺序点;
10)for循环控制条件中的两个分号处各有一个顺序点。
对于任意一个顺序点,它之前的所有副作用都已经完成,它之后的所有副作用都尚未发生。
在两个顺序点之间,子表达式求值和副作用的顺序是不同步的。如果代码的结果与求值和副作用发生顺序相关,称这样的代码有不确定的行为(unspecified behavior).而且,假如期间对一个内建类型执行一次以上的写操作,则是未定义行为.
任意两个顺序点之间的副作用的发生顺序都是未定义的.
如:
x=x++;
该表达式只有一个顺序点,在该顺序点之前有2个副作用,一个是自增,一个赋值,这两个副作用发生的顺序是未定义的,即自增运算和赋值运算哪一个先执行是没有被定义的(注意这个顺序跟运算符的优先级是无关的,注意理解运算符优先级的含义),这个执行次序交由编译器厂商去自行决定,因此对于不同的编译器可能会得出不同的结果。
#include <stdio.h>
#include <stdlib.h> int main(int argc, char*argv[])
{
int i=;
int m=(++i)+(++i)+(++i)+(++i);
printf("%d %d\n",m,i);
system("pause");
return0;
}
对于上述代码:
在gcc编译器中运行得到的结果是 11 4
而在Visual Studio 2008中运行得到的结果是 16 4
因为对于
int i=0;
int m=(++i)+(++i)+(++i)+(++i);
在两个分号之间有5个副作用,这5个副作用与子表达式的求值顺序是未定义的,对于不同的编译器会得出不同的结果。
并且在这期间对i进行了不止一次的写操作,这也是一个未定义的行为,可能会引起任何后果。
还比如:
x[i]=i++;
printf("%d %d\n",i++,i++);
function(x,x++);
这些都是未定义的行为。
因此我们平时在写代码时,尽量不要写出这样风格不好的代码,因为它不仅会给程序带来不确定性,可能会引起任何后果(比如程序崩溃),而且对于代码的移植性来说是致命的打击。
比如:
x[i]=i++;
可以用这段代码去代替:
x[i]=i;
i++;
function(x,x++);-> function(x,x);x=x+1;
这样的代码才是风格良好的代码。
尽量保证,在两个相邻顺序点之间同一个变量不可以被修改两次以上或者同时有读取和修改,否则,就会产生未定义的行为。
[转载]C++的顺序点(sequence point)和副作用(side effect)的更多相关文章
- 顺序图(Sequence Diagram)
顺序图(Sequence Diagram): 是一种强调对象间消息传递次序的交互图,又称为时序图或序列图.描述了在一个用例或操作的执行过程中对象如何通过消息相互交互,说明了消息如何在对象之间被发送和接 ...
- C#线性表之顺序表
线性表是最简单.最基本.最常用的数据结构.线性表是线性结构的抽象(Abstract), 线性结构的特点是结构中的数据元素之间存在一对一的线性关系. 这种一对一的关系指的是数据元素之间的位置关系,即: ...
- 浅谈C/C++中的顺序点和副作用
一.副作用(side effect) 表达式有两种功能:每个表达式都产生一个值( value ),同时可能包含副作用( side effect ).副作用是指改变了某些变量的值. 如: 1:20 ...
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- UML之顺序图(时序图)
1 顺序图 1.1 顺序图的概念 顺序图(sequence diagram): 用来描述为了完成确定事务,对象之间按照时间消息交互的顺序关系. 1.2 顺序图样式和元素 (1) 对象及命名 (2) 生 ...
- XML详解:第二部分 XML Schema
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- C语言的一些常见细节
C语言的一些常见细节 对于C语言,不同的编译器采用了不同的实现,并且在不同平台上表现也不同.脱离具体环境探讨C的细节行为是没有意义的,以下是我所使用的环境,大部分内容都经过测试,且所有测试结果基于这个 ...
- Activiti进行时——企业工作流生命周期贯通 (zhuan)
http://www.jianshu.com/p/e6971e8a8dad ********************************************** 图1:一个典型的审批工作流程 ...
- STL使用总结
转载于http://blog.csdn.net/daisy_chenting/article/details/6898184 1. 概述 泛型编程思想最早缘于A.Stepanov提出的部分算法可 ...
随机推荐
- TensorFlow入门(五)多层 LSTM 通俗易懂版
欢迎转载,但请务必注明原文出处及作者信息. @author: huangyongye @creat_date: 2017-03-09 前言: 根据我本人学习 TensorFlow 实现 LSTM 的经 ...
- Ext.js Combobox 输入模糊匹配
前台页面 aspx: 数据源: <ext:Store ID="storeJF" runat="server" AutoLoad="true&qu ...
- ubuntu12.04安装squid
一:简介 1.Squid:优化Web交付 Squid是支持HTTP,HTTPS,FTP等的Web的缓存代理.它通过缓存和重用经常请求的网页来减少带宽并缩短响应时间.Squid拥有广泛的访问控制,是一个 ...
- Flask使用Flask-SQLAlchemy操作MySQL数据库
前言: Flask-SQLAlchemy是一个Flask扩展,简化了在Flask程序中使用SQLAlchemy的操作.SQLAlchemy是一个很强大的关系型数据库框架,支持多种数据库后台.SQLAl ...
- HTTP协议冷知识大全
如果不用HTTPS,HTTP协议如何安全的传输密码信息? HTTP协议是纯文本协议,没有任何加密措施.通过HTTP协议传输的数据都可以在网络上被完全监听.如果用户登陆时将用户名和密码直接明文通过HTT ...
- 四则运算 C 语言
#include<stdio.h>void main(){ char c; float x,y; int result; scanf("%c %f %f",&c ...
- IO学习
---恢复内容开始--- 命名规则: 1.类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:(领域模型 的相关命名)DO / BO / DTO / VO 等. 2.方法名 ...
- jQuery中empty与html("")的区别对比
简单的说empty,首先循环给后代元素移除绑定(释放内存).清除jquery给此dom的cache,然后循环removeFirstChild,而html(''),则是简单暴力的设置innerHTML ...
- FTP Download File By Some Order List
@Echo Off REM -- Define File Filter, i.e. files with extension .RBSet FindStrArgs=/E /C:".asp&q ...
- Ping命令的另一种使用方法
今天实习结束休息的时候无聊,于是便想看看机房有多少机器,IP是什么,有没有什么小漏洞. 依次使用了netstat.ping.Telnet以后,不小心输入了这样一个东西 当时按下回车以后,心里想的是这样 ...