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++编程语言实现表达式求值的功能。这是一个典型的数据结构与算法问题,尤其适用于计算机科学与信息技术专业的学生进行实践学习。C++是一种强大的编程语言,它提供了丰富的特性来...
本文旨在深入探讨C/C++语言中表达式的求值机制,特别是涉及表达式的计算过程、副作用以及顺序点的概念。文章将详细解释这些概念,并通过具体示例来帮助读者更好地理解这些复杂的概念。 #### 二、表达式求值的基础 ...
本篇文章将深入探讨C++中JSON的序列化与反序列化。 **一、JSON序列化** 序列化是指将C++的对象转换为JSON字符串的过程,以便在网络上传输或保存到文件中。常见的C++ JSON序列化库有RapidJSON、nlohmann/json、...
在本项目中,我们主要关注的是使用Qt C++进行时间序列分析。Qt是一个跨平台的C++应用程序开发框架,广泛应用于GUI(图形用户界面)设计和系统编程。时间序列分析是一种统计技术,它涉及到对数据点按时间顺序排列的...
语义分析器是编译器设计中的一个重要组成部分,它在编译过程中扮演着至关重要的角色。编译原理是一门深入探讨计算机程序如何被转换为机器可执行代码的学科,而语义分析是其中的关键阶段。在这个阶段,编译器不仅检查...
语义分析是编译器设计中的关键步骤,它在C++编程中扮演着重要的角色。在C++中,语义分析是在词法分析和语法分析之后进行的,目的是确保程序的逻辑正确性,即检查代码的含义是否符合C++语言的语法规则。在这个过程中...
根据给定的信息,本文将对"C++模糊逻辑代码实现"这一主题进行深入解析。模糊逻辑是一种处理不精确信息的方法,其在很多领域如人工智能、控制理论等都有着广泛的应用。接下来,我们将逐步分析并理解该段代码所涉及的...
在C/C++中,由于没有内置的序列化支持,开发者通常需要自定义实现。本主题探讨的是如何利用C++的模板机制来实现结构体的序列化配置,以提高代码的可复用性和灵活性。 首先,我们需要理解C++的模板。模板是C++中的一...
但由于之前我设计文法大多只是为了测试使用,所以文法很不规范,这直接导致了语义子程序十分难实现,所以要想实现一个好的语义分析器,必须先设计好你的文法。 需要注意的是,这个语义分析器是建立在我之前写的语法...
在C++实现中,这些输入可能通过传感器或其他数据源获取,并转换为模糊集合的语言值。 2. **隶属度函数**:模糊逻辑的核心在于将实数值映射到模糊集的隶属度。常见的隶属度函数包括三角形、梯形、高斯等,可以根据...
2. **表达式求值**:虽然简单的算术运算在语法分析阶段可能已经被解析为抽象语法树(AST),但语义分析会进一步处理这些表达式,如计算常量表达式的值,或者确定变量的最终类型。 3. **作用域解析**:语义分析器还...
本资源使用C++实现了语义分析器,内容包括C++源代码与exe文件、input.txt和程序运行说明文档。该资源的文字版信息请访问博客《编译原理实践:C++实现语义分析器(学习笔记)》...
这篇内容我们将深入探讨C++中的JSON序列化,基于提供的资源,我们可以推测这是一个关于如何在C++中实现JSON序列化的项目实例。 首先,让我们理解JSON的基本结构。JSON格式通常包含键值对(key-value pairs)和数组...
C++实现序列化,简单的讲是将C++里的对象(此处是广义上的对象,内置类型或者用户自定义类型)数据变成char*,即单个字节的数据,这样方便传输等,涉及到的知识点有C++中的函数重载,操作符重写,allcotor,左值和...
在程序设计中,可能碰到需要对字符串数学表达式求值的问题,常用的方法是解析表达式,生成二叉树,然后进行计算。编译器就是使用这种方法来解析程序中的表达式的。这种方法实现起来有点难度,需要考虑运算符的优先级...
在这个场景中,我们讨论的是动态规划算法在C++语言中的实现,特别应用于两个蛋白质序列的比对。蛋白质序列比对是生物信息学中的一个核心问题,它有助于研究蛋白质的功能、结构以及进化关系。 首先,我们需要理解...
C++11的新特性。尤其是lamda表达式,使得C++灵活了很多
在C++中,求解特征值和特征向量通常依赖于数值线性代数库,如开源的Eigen库。Eigen库提供了丰富的接口,用于处理各种线性代数问题,包括计算矩阵的特征值和特征向量。"matrixl(eig)"这个文件名可能暗示了它使用了...
在C++中实现自适应模糊PID控制,通常涉及到以下几个关键知识点: 1. **PID控制器**:PID(比例-积分-微分)控制器是最常用的自动控制算法之一,通过调整比例(P)、积分(I)和微分(D)三个参数来控制系统的响应。...
在编译原理中,算符优先文法是一种用于解析程序语法结构的重要工具,它通过定义运算符的优先级和结合性来决定表达式的求值顺序。在这个试验代码中,我们看到作者使用C++语言实现了算符优先文法的语义分析部分。下面...