C++中的求值|副作用|序列点所导致的模糊语义
前一阵子一个偶然的机会,在soloist的blog上(http://blog.csdn.net/soloist)看到一篇关于C/C++中的一个十分历史悠久的问题的讨论,即表达式求值的问题。说实话这个问题着实不新鲜了,被所有论坛提出过无数次,无非就是表达式求值顺序不确定的问题嘛。所以我也就没太在意,soloist那里吵翻了天,说什么的都有,热闹非凡。
当时我就当复习一下,想看看标准对这一块到底有什么明确的说法,就随手翻开了[C++03],结果发现原来情况并非像很多人,乃至我所长期以来认为的那样,简而言之,有下面几个令人意外的结果,不但令我意外,当我把问题发到comp.std.c++新闻组上之后居然引起了一场不大不小的争吵,Andrew Koenig、Herb Sutter、David Abrahams、P.J Plauger...,于是我就看了几天的连台好戏,同时也把这个问题的答案在脑子里刷新了一次。
下面就是两个令人感到意外的现象:
1. 表达式求值并不一定意味着求值过程中的副作用会同步发生!这是一个违反直觉的地方,带来了非常晦涩的语义。
2. i = (i++); 这种极度简单的表达式的行为居然是未定义的(undefined behavior)『注意“未定义行为(undefined behavior)”跟“未指定行为(unspecified behavior)”之间的重大区别。前者是对于不正确的,有毛病的程序而言,未定义行为可能是任何行为,轻则出现意料之外的结果,重则程序崩溃(崩溃还算好的,糟的就是错了还一声不吭^_^)。后者则是对于well-formed程序而言,未指定(unspecified)行为的可能性一般是有限的(例如函数参数的求值顺序就是函数参数个数的全排列种),只不过具体的实现不用在文档里说明究竟在它的实现上的特定行为是怎样的。』 顺便提一下“由实现定义的行为(implementation defined)”,这一行为跟“unspecified behavior”比较类似,都是针对well-formed程序而言,只不过后者的具体行为需要特定实现注明在文档中,让用户知道。 我们一直以为i=(i++)的行为是unspecified,即以为它至少还是well-formed程序,只不过在不同编译器上有不同结果罢了,然后结果却大谬不然,其行为是undefined,可能产生任何结果(从概念上来说,甚至可能导致程序崩溃^_^)。
3. i = (i++)这种表达式如果i是用户自定义迭代器的话,其行为却又变成了 unspecified,甚至由于这里左端表达式并没有实际的side-effect,所以其结果甚至是 定 的!这就是说,在build-in operation跟user-defined operator之间某些情况下存在着不易察觉的隐晦差别。
多的就不说了,带着上面的看法,你可以去看看我发在comp.std.c++上的帖子,地址如下:
标题:Is this really unspecified behavior?
http://groups.google.com/group/comp.std.c++/browse_frm/thread/0174aa7b34b06a51/581d5219d5a75578#581d5219d5a75578
分享到:
相关推荐
C++求最大子序列的和 问题:求一个数组 / 序列的满足条件的子数组 / 子序列。 条件: 1. 子数组必须是连续的。 2. 求和即可,不需要返回子数组是哪段。 3. 数组元素为整数。
c++行列式求值源码。。
C++求最长公共子序列!实用 花费了好长时间!!
但由于之前我设计文法大多只是为了测试使用,所以文法很不规范,这直接导致了语义子程序十分难实现,所以要想实现一个好的语义分析器,必须先设计好你的文法。 需要注意的是,这个语义分析器是建立在我之前写的语法...
C++ JSON 序列化与反序列化 相关的博客文章见:http://blog.csdn.net/TragicGuy
C++语法语义分析器 本程序在屏幕上输入待分析的C语言 赋值 语句 格式: begin(请一定输入,否则不能运行) s=...; a=...; b=...; end #(结束符号) 输出三地址指令: t1=... t2=... s=...
里面包含数据结构代码和实现表达式求值的代码,结构一目了然! 还包括实验报告!适用于学生!
C++模糊查询实现,C++模糊查询实现,原代码说明
本资源使用C++实现了语义分析器,内容包括C++源代码与exe文件、input.txt和程序运行说明文档。该资源的文字版信息请访问博客《编译原理实践:C++实现语义分析器(学习笔记)》...
LiteSeg语义分割的模型和源码,使用OpenCV 的Dnn进行推理
语义分析 C++ 编译原理 运行环境:Visual Studio 2005
数据结构课程实验 可用c++源代码 已知先序后序序列求中序序列的可运行源代码
C++实现序列化,简单的讲是将C++里的对象(此处是广义上的对象,内置类型或者用户自定义类型)数据变成char*,即单个字节的数据,这样方便传输等,涉及到的知识点有C++中的函数重载,操作符重写,allcotor,左值和...
C++ qt时间序列分析代码,该代码是用于vs,作为时间序列分析的,直接可用,需要输入的是已知数据及预测数据等等
使用C++实现的编译原理课程中的语义分析 根据一段表达式 计算出其四元式
在程序设计中,可能碰到需要对字符串数学表达式求值的问题,常用的方法是解析表达式,生成二叉树,然后进行计算。编译器就是使用这种方法来解析程序中的表达式的。这种方法实现起来有点难度,需要考虑运算符的优先级...
CArchive类的简单用法,实现C++序列化和反序列化存储,简单明了
用C++实现的遗传算法求函数的最大值,可运行
语义分析器,编译原理课程设计,c++,c,很不错的哦
C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++