有关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)的更多相关文章

  1. 顺序图(Sequence Diagram)

    顺序图(Sequence Diagram): 是一种强调对象间消息传递次序的交互图,又称为时序图或序列图.描述了在一个用例或操作的执行过程中对象如何通过消息相互交互,说明了消息如何在对象之间被发送和接 ...

  2. C#线性表之顺序表

    线性表是最简单.最基本.最常用的数据结构.线性表是线性结构的抽象(Abstract), 线性结构的特点是结构中的数据元素之间存在一对一的线性关系. 这种一对一的关系指的是数据元素之间的位置关系,即: ...

  3. 浅谈C/C++中的顺序点和副作用

    一.副作用(side effect) 表达式有两种功能:每个表达式都产生一个值( value ),同时可能包含副作用( side effect ).副作用是指改变了某些变量的值. 如: 1:20    ...

  4. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  5. UML之顺序图(时序图)

    1 顺序图 1.1 顺序图的概念 顺序图(sequence diagram): 用来描述为了完成确定事务,对象之间按照时间消息交互的顺序关系. 1.2 顺序图样式和元素 (1) 对象及命名 (2) 生 ...

  6. XML详解:第二部分 XML Schema

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  7. C语言的一些常见细节

    C语言的一些常见细节 对于C语言,不同的编译器采用了不同的实现,并且在不同平台上表现也不同.脱离具体环境探讨C的细节行为是没有意义的,以下是我所使用的环境,大部分内容都经过测试,且所有测试结果基于这个 ...

  8. Activiti进行时——企业工作流生命周期贯通 (zhuan)

    http://www.jianshu.com/p/e6971e8a8dad ********************************************** 图1:一个典型的审批工作流程 ...

  9. STL使用总结

    转载于http://blog.csdn.net/daisy_chenting/article/details/6898184 1.    概述 泛型编程思想最早缘于A.Stepanov提出的部分算法可 ...

随机推荐

  1. BJOI2018简要题解

    BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...

  2. Html页面雪花效果的实现

    简单介绍 昨天修改了一下博客所用的模板,冬天来了,给自己的博客加点雪花,感觉更有意境. 百度找到了非常多的结果,最终还是选用了cfs.snow.js,很赞压缩之后只有1kb左右,而且不会影响页面使用, ...

  3. 使用Hexo+Github搭建属于自己的博客(基础)

    前言 hexo是一个台湾人做的基于Node.js的静态博客程序,优势是生成静态文件的速度非常快,支持markdown, 我最终选定它的原因是它速度快而且不容易出错,并且可以一键部署到github或者其 ...

  4. @Vue/Cli 3 关于 render 空的处理

    问题场景 vue-cli 3 在打包部署时候会出现 dist folder not working "Uncaught TypeError: Cannot set property 'ren ...

  5. [UWP 自定义控件]了解模板化控件(4):TemplatePart

    1. TemplatePart TemplatePart(部件)是指ControlTemplate中的命名元素.控件逻辑预期这些部分存在于ControlTemplate中,并且使用protected ...

  6. Linux内核分析— —构造一个简单的Linux系统MenuOS(20135213林涵锦)

    Linux内核分析— —构造一个简单的Linux系统MenuOS 实验内容 Linux内核的启动过程,从start_kernel到init进程启动 使用实验楼的虚拟机打开shell cd LinuxK ...

  7. 《Linux内核设计与实现》 第三章学习笔记

    一.进程 1.进程就是处于执行期的程序(目标码存放在某种存储介质上).但进程并不仅仅局限于一段可执行程序代码,通常进程还要包含其他资源.执行线程,简称线程(thread),是在进程中活动的对象. 2. ...

  8. github 学习心得

    https://github.com/kongxiangyu/test 通过本次实验,学会了如何使用github来管理代码.如果是开源的项目,通过网站托管方式进行统一管理,当然是非常棒的,并且有很多功 ...

  9. HDOJ2041_超级楼梯(斐波拉契数列)

    正常简单题:通过仔细观察推断即可看出这是一个斐波拉契数列的题目. HDOJ2041_超级楼梯 在做这题的时候我误入了思维盲区,只想着什么方法可以解决,没有看出是斐波拉契数列.因此第一次用组合数方法打了 ...

  10. Install Kernel 3.10 on CentOS 6.5

    http://bicofino.io/2014/10/25/install-kernel-3-dot-10-on-centos-6-dot-5/ https://gree2.github.io/lin ...