C语言序列点浅析
摘要:
现行国内的C语言教材普遍不介绍序列点,这使得读者只能“死记硬背”有序列点表达式的求值顺序,不仅造成了读者对C语言知识的认知残缺不全,而且也影响了读者学习的积极性。本文总结了序列点的作用,即表达式求值时需考虑序列点的影响,序列点左边的操作数要先于其右边的操作数求值。结合操作符的作用,分析了逗号操作符,、逻辑与操作符&&、逻辑或操作符||和条件操作符?:的问号处?为什么会有序列点。
关键字:序列点 表达式 C语言
C语言是最重要的结构化程序设计语言,许多编程语言如Java、C++、C#都借鉴了C语言的语法。随着数字化信息技术的发展和网络环境的形成,计算机已渗透到各行各业,为了更好地了解和使用计算机,国内大专院校的许多理工类专业都开设了C语言课程,因此,C语言的教学水平影响着许许多多的学生。
现行国内的C语言教材通常不介绍序列点,这使得读者只能“死记硬背”有序列点表达式的求值顺序。以简单的逗号表达式为例,设变量a为整型变量(下文中出现的变量a也为整型变量),在分析表达式a = 3, ++a的求值顺序时强调“逗号表达式自左向右依次求值”,而在分析表达式求值的原则时强调根据操作符的优先级和结合性确定求值顺序。即使表达式中自增操作符++的优先级最高,也要先对子表达式a=3求值,该怎样向学生解释这与求值原则矛盾的“求值顺序”呢?
1序列点的定义及分析
根据C语言标准[1][2][3],序列点就是执行序列中的一些特定点,在这些点上,前面求值的副效应(side effect)应彻底完成且其后求值的副效应均未发生。在教材中照搬标准让初学者学习理解序列点这个概念是不明智的,应直接向初学者指出序列点在表达式求值中起的作用。C语言表达式求值的原则为:根据操作符的优先级和结合性确定表达式的求值顺序,但求值时要考虑序列点的影响,需保证序列点左边的操作数先于其右边的操作数求值。
2操作符的操作数
操作数是指操作符进行操作的操作对象,如表达式3+2中加法操作符左边的操作数为3,右边的操作数为2。在复杂的表达式中,需结合操作符的优先级和结合性来确定某操作符的操作数。对于表达式3+2*5,加法操作符左边的操作数为3,但其右边的操作数不为2,因为进行加法运算时3不可能和2相加,其右边的操作数为2*5(的积);而乘法操作符左边的操作数为2,右边的操作数为5。
表达式a = 0 && ++a中逻辑与左边的操作数为0,右边的操作数为子表达式++a,整个表达式为赋值表达式;而表达式(a = 0) && ++a中逻辑与左边的操作数为子表达式(a = 0),右边的操作数为子表达式++a,整个表达式为逻辑表达式。
3C语言中有序列点的操作符
逗号操作符,有序列点。逗号操作符的作用为把多条语句变成一条语句,如a = 2;和++a;为两条语句,而a = 2, ++a;是一条语句。语句a = 2, ++a;执行时,如果逗号操作符没有序列点,子表达式++a就会先执行,即这条语句的执行顺序与上面两条语句的并不相同。基于逗号操作符的作用,逗号操作符只能优先级最低,且含有序列点。
逻辑与操作符&&有序列点。C语言中逻辑与操作符会“短路计算”,即当其左边的操作数为假时,不对右边的操作数求值而直接把0(假)作为结果。表达式3>5 && ++a求值时,如果逻辑与操作符没有序列点,子表达式++a就会先执行,即逻辑与操作符的短路计算名存实亡。为了短路计算,逻辑与操作符&&需序列点。求值时需保证序列点左边的操作数要先于其右边的操作数求值,故表达式3>5 && ++a中逻辑与操作符左边的操作数先求值,即子表达式3>5先求值,结果为0,即假,由于短路计算,整个表达式的值为0,即假,且右操作数子表达式++a不会被求值。
逻辑或操作符||有序列点。C语言中逻辑或操作符也会“短路计算”,因此,其有序列点的必要性与逻辑与的相同。
条件操作符?:的问号处?有序列点。条件操作符用于改写简单的if-else选择结构,如下面的语句(设变量b为整型变量)
if(a > b)
++a;
else
++b;
可用条件操作符改写为a > b ? ++a : ++b;。
如果条件操作符没有序列点,语句a > b ? ++a : ++b;执行时,++a和++b会先于子表达式a > b执行,这样的执行顺序显然与if-else选择结构的不同,因此,条件操作符?:的问号处?有序列点。语句a > b ? ++a : ++b;执行时,问号处?左边的操作数a > b先执行,值为真时,对++a求值,不对++b求值;值为假时,正好相反。
4结束语
虽然C语言表达式种类繁多,但表达式求值时有着相对明确的求值规则,只要根据求值规则分析,再奇特的表达式也不会成为学习上的难点。表达式求值时需考虑序列点的影响,忽视它的存在就不能正确地分析C语言表达式的求值顺序,只能让学生“死记硬背”,影响学习积极性。在教材中直接引入序列点的概念势必会增加学习的难度,从序列点在表达式求值中的作用入手,给初学者提供一个容易理解的序列点概念,不仅不会造成C语言知识点的残缺,而且也为“启发式教学”提供了可能,如可以引导初学者分析操作符为什么要有序列点。
参考文献
[1] International Organization for Standardization. ISO/IEC 9899:1999.
[2] International Organization for Standardization. ISO/IEC 9899:1990.
[3]国家技术监督局. GB/T 15272-94 程序设计语言 C. 1994
[4]周二强. C语言内涵教程[M]. 中国铁道出版社 2013.
C语言序列点浅析的更多相关文章
- C语言序列点问题总结(大多数高等教育C语言教学课程的漏洞)
C语言序列点总结 2013年11月21于浙大华家池 C 语言副作用: (side effect)是指对数据对象或者文件的修改. 例如,语句 v = 99;的副作用是把 v 的值修改成 99. C语言序 ...
- ReactiveX序列——RxSwift 浅析
ReactiveX序列——RxSwift Swift是苹果公司新推出的一门现代化的编程语言,并且将其开源出来了,Swift具有很多的优点,这也使得这门语言推出的短时间引起了很大反应的原因,在最近的 ...
- C语言之goto浅析
1. 读代码时遇了的疑惑点: static int do_bind(const char *host, int port, int protocol, int *family) { int fd; ...
- C语言 序列反向互补函数
1 static char *revers(char *s) 2 { 3 int len=strlen(s); 4 char *s2=(char *)malloc(sizeof(char)*(len+ ...
- 10. Go 语言反射
Go 语言反射 反射是指在程序运行期对程序本身进行访问和修改的能力.程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分.在运行程序时,程序无法获取自身的信息. 支持反射的语言可以在 ...
- MTU-TCP/IP协议栈-linux kernel-TCP丢包重传-UDP高性能-AI-
http://view.inews.qq.com/a/20161025A0766200窄带时代的QQQQ是窄带时代极具代表性的产品,在那个网络传输效率比较低的年代,大家还记得Google的首页吗?Go ...
- python的编码问题研究------使用scrapy体验
python转码译码 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !impo ...
- [转]语言模型训练工具SRILM
SRILM是一个建立和使用统计语言模型的开源工具包,从1995年开始由SRI 口语技术与研究实验室(SRI Speech Technology and Research Laboratory)开发,现 ...
- 【OCR技术系列之五】自然场景文本检测技术综述(CTPN, SegLink, EAST)
文字识别分为两个具体步骤:文字的检测和文字的识别,两者缺一不可,尤其是文字检测,是识别的前提条件,若文字都找不到,那何谈文字识别.今天我们首先来谈一下当今流行的文字检测技术有哪些. 文本检测不是一件简 ...
随机推荐
- C语言宏的高级应用
原文:C语言宏的高级应用 关于#和##在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号.比如 ...
- MFC 界面编程 可参考资料
http://www.codeproject.com/Articles/26887/A-user-draw-button-that-supports-PNG-files-with-tr http:// ...
- POJ 1284 Primitive Roots 原根
题目来源:POJ 1284 Primitive Roots 题意:求奇素数的原根数 思路:一个数n是奇素数才有原根 原根数是n-1的欧拉函数 #include <cstdio> const ...
- Unity3d在线游戏Socket通讯
网络游戏是一个人的互动娱乐软件应用.因为它是交互式,当然,需要了解对方的通信.这需要通信Socket:我们今天要实现的主角即套接字.Socket的英文原义是"孔"或"插座 ...
- 根据当前登录域账号 获取AD用户姓名和所在OU目录
#region 根据当前登录域账号 获取AD用户姓名和所在OU目录 /// <summary> /// 根据当前登录域账号 获取AD用户姓名和所在OU目录 返回域用户是否存在 /// &l ...
- linux之stat函数解析
[lingyun@localhost stat_1]$ vim stat.c + stat.c ...
- GridView中两个DropDownList联动
GridView中两个DropDownList联动 http://www.cnblogs.com/qfb620/archive/2011/05/25/2057163.html Html: <as ...
- socket串口通信
SocketServer: #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #inclu ...
- SZU:L89 Frog Encoding
Judge Info Memory Limit: 65536KB Case Time Limit: 3000MS Time Limit: 3000MS Judger: Normal Descripti ...
- c++对象内存布局的理解
我对c++对象内存布局的理解 引言 结合网上的一些资料,通过自己的一番摸索,得出了一点个人见解.现在写下来,希望与各位同学共同探讨,共同进步. 以下所有代码均是在VS2012下测试. 一个普通的基 ...