本文是 本系列的第三篇,本文主要对C语言的表达式做个小结

先从两个坑爹的表达式说起:i++ 与++i

上大学的时候,学长告诉我,这两个表达式,意义是一样的,后来老师纠正说,还是有区别的,于是让我们记住以下观点:i++是先使用i的值,再对i进行+1操作,而后者则刚好相反,先将i+1,再使用i的值。一直都是这么记得,笔试也没错过,也就信了老师了。更合理的解释是:++i在存储的值上增加1 并向使用它的表达式“返回”新的、增加后的值,而i++对i增加1,但返回的是原来的、未增加的i的值。

但是,据本书所解释的: i++ 或者i--在输出其旧值才会执行运算,但这里的“之后”的含义和准确定义常常被误解,无法保证自增或者自减会在放弃变量原值之后和对表达式的其他部分进行计算之前立即进行,只能保证变量的更新会在表达式“完成”之前的某个时刻进行。

回到学长的观点,以下语句的有区别么?

for (int i = 0;i<5;i++)

for (int i = 0;i<5;++i)

从达到的目的上看,确实没有区别。都实现了i的递增加1 ,但是linux之父 linus告诉我们,后者比前者的运行效率更高,因为后者没有产生中间量,在很多次的运行中,这种差异还是有的,于是,我相信了,以后在我所有的循环自加的语句中都使用++i的形式。这在C++中 ,区别就更加明显了,不信可以重构下++ 操作符,如果你也懂C++的话。

现在思考以下表达式:

a[i] = i++;

a[i] = ++i;

这种计算依赖于计算机编译器,在我的x86_64-w64-mingw32-gcc编译下,二者遵循老师的运算逻辑,但是,这样的代码是应该避免的,毕竟,我们并不怕多一个中间变量。

是的,凡是与表达式相关的不清晰的表达,都可以用增加中间变量来解决。

a[i] = i++;=====> j = i;a[i] = j; i++;

a[i] = ++i;=====> j = i+1;a[i] = j;i++;

表达式 自身的 运算以及 运算符的优先级问题 本身不应该成为问题,这样的问题 最好还是留在笔试题目中,我们在实际编码中,更关心代码的清晰度和易读性,因此,不建议乱用高级的表达式来达到 简单化代码的目的,实在要用,可以多用括号表达。

于是,有以下建议可以避免未定义的求值顺序问题:

1.确保一个表达式最多只修改一个对象:一个简单变量、一个数组成员或者一个指针指向的位置,“修改”是指=操作符的简单赋值,+=、-=或者*=操作符的复合赋值或者++ --操作符的前后缀形式

2.如果一个对象在一个表达式 中出现一次以上 而且在表达式中被修改,则要确保该对象的所有读访问都被用于计算它的最终值,这条规则允许表达式i=i+1 ——尽管i出现两次而且也被修改了,但对i的旧值是用于计算i的新值

3.如果想要破坏第一条规则,就要确保修改的对象互不相同。表达式c = *p++是合法的,因为修改的两个对象c和p互不相同,

4.如果在两次修改或者修改和访问之间置入定义的序列点操作符,则可以破坏第一条规则和第二条规则,这个表达式(通常在一个while循环中看到,用来读入一行的内容)是合法的,因为 第二次访问变量c出现在&&引入的序列点之后。

(c = getchar()) != EOF && c != '\n'

其他知识

  • && 与|| 的短路规则,
  • 左值 与 右值 ,可赋值变量

你必须知道的495个C语言问题,学习体会三的更多相关文章

  1. 你必须知道的495个C语言问题,学习体会一

    C语言作为一门古老的语言,其灵活性和容易出错都让人 又爱又恨,书籍<你必须知道的495个C语言问题>,使用问答的形式,告诉读者 C语言使用的各个方面的知识,包括一些冷知识等.以下,我要摘录 ...

  2. C语言学习书籍推荐《你必须知道的495个C语言问题》

    萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...

  3. 《你必须知道的495个C语言问题》知识笔记及补充

    1. extern在函数声明中是什么意思? 它能够用作一种格式上的提示表明函数的定义可能在还有一个源文件里.但在 extern int f(); 和 int f(); 之间并没有实质的差别. 补充:e ...

  4. 你必须知道的495个C语言问题,学习体会四

    本文,我们来学习下指针,这是个梦魇啊.无数次折磨着C语言学习者,无数次的内存泄露,无数次的访问失败,无数次的越界溢出, 这些错误造就的仅仅是一个 跟随者,真正的优秀者必须要正视语言的局限,同时在最大限 ...

  5. 你必须知道的495个C语言问题,学习体会二

    这是本主题的第二篇文章,主要就结构体,枚举.联合体做一些解释 1.结构体 现代C语言编程 结构化的基石,diy时代的最好代言人,是面向对象编程中类的老祖宗. 我们很容易定义一个结构体,比如学生: st ...

  6. 你必须知道的495个c语言问题(笔记)

    1.1我该如何决定使用哪种整数类型? 用到较大的数用long:空间很重要(例如有很大的数组或很多的结构)用short:此外用int. win32: int 32bit    4byte char 8b ...

  7. 《你必须知道的495个C语言问题》读书笔记之第11-14章:ANSI C标准、库函数、浮点数

    一.ANSI C标准 1. ANSI向C语言预处理器引入了几项新的功能,包括“字符串化”操作符(#).“符号粘贴”操作符(##).#pragma指令. 2. Q:char a[3] = "a ...

  8. 《你必须知道的495个C语言问题》读书笔记之第8-10章:字符串、布尔类型和预处理器

    一.字符和字符串 1. Q:为什么strcat(string, '!')不行? A:strcat()用于拼接字符串,所以应该写成strcat(string, "!")." ...

  9. 《你必须知道的495个C语言问题》读书笔记之第4-7章:指针

    1. Q:为什么我不能对void *指针进行算术运算? A:因为编译器不知道所值对象的大小,而指针的算法运算总是基于所指对象的大小的. 2. Q:C语言可以“按引用传参”吗? A:不可以.严格来说,C ...

随机推荐

  1. Spring mvc 具体RequestMapping 参数含义

    今天遇到碰到有人问我个问题,RequestMapping中参数的意义,哎呀傻眼了,果断查资料,这下知道了. http://blog.csdn.net/kobejayandy/article/detai ...

  2. jsp、freemarker、velocity对比

    在java领域.表现层技术主要有三种:jsp.freemarker.velocity. jsp是大家最熟悉的技术长处:1.功能强大,能够写java代码2.支持jsp标签(jsp tag)3.支持表达式 ...

  3. ros使用时的注意事项&技巧

    1.rosrun package-name executable-name 比如 rosrun turtlesim turtlesim_node 2.一旦启动roscore后,便可以运行ROS程序了. ...

  4. 【c++ primer, 5e】访问控制与封装

    练习 7.16 无,类的接口定义在public说明符之后,类的实现细节定义在private说明符之后. 7.17 有.类成员的默认访问权限不同.class的类成员默认为private,struct的则 ...

  5. QMesageBox的使用

    一.使用构造函数弹出对话框 1. QMessageBox msgBox://最简单的对话框,里面什么也没有 QString str = “test”: msgBox.setText(str); msg ...

  6. SpringBoot 定义通过字段验证

    第一步:定义ValidationResult类 public class ValidationResult { // 校验结果是否有错 private boolean hasErrors = fals ...

  7. HTML常用标签——思维导图

    如图 思维导图图片链接 http://www.edrawsoft.cn/viewer/public/s/38d99149304484

  8. 未来简史之数据主义(Dataism)

    https://www.jianshu.com/p/8147239c9cb0?from=singlemessage junjguo 关注 2017.04.24 22:08* 字数 8116 阅读 31 ...

  9. BZOJ4456/UOJ184 [Zjoi2016]旅行者

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  10. tyvj 1059 过河 dp

    P1059 过河 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 NOIP2005 提高组 第二道 描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳 ...