本文是 本系列的第三篇,本文主要对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. shell文件安全与权限 笔记

    主要学习: 文件盒目录的权限 Setuid Chown和chgrp Umask 连接符号 一个文件已经创建,就具有三种访问方式 读,可以显示该文件的内容 写,可以编辑或删除它 执行,如果该文件时一个s ...

  2. Linux系统服务管理 系统服务

    服务的分类 Linux 中的服务按照安装方法不同可以分为 RPM 包默认安装的服务和源码包安装的服务两大类.其中,RPM 包默认安装的服务又因为启动与自启动管理方法不同分为独立的服务和基于 xinet ...

  3. Loopback接口的作用

    Loopback接口是虚拟接口,是一种纯软件性质的虚拟接口.任何送到该接口的网络数据报文都会被认为是送往设备自身的.大多数平台都支持使用这种接口来模拟真正的接口.这样做的好处是虚拟接口不会像物理接口那 ...

  4. Sybase:删除表中的某列

    Sybases:删除表中的某列 alter table tb1(表名) drop clo1(列名); commit;

  5. HDU 5703

    题意:给你一个数n,问将n分为正整数和的方案数.如n=3共四种,1 1 1 , 1 2 , 2 1 ,3 . 思路:隔板法,n个1,有n-1个空位,每个空位可以选择是否插入隔板,插入k(0<=k ...

  6. resultMap结果集映射

    resultMap结果集是用来定义sql查询的结果与java对象的映射关系.它主要解决2大问题: 1)可以解决POJO属性名和表结构的字段名不一致问题(甚至是 不是标准的驼峰命名法) 2)可以完成高级 ...

  7. [CTSC2008]祭祀river

    Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都 会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组 ...

  8. 团体程序设计天梯赛 L2-018. 多项式A除以B(模拟)

    题意:给你A,B两个多项式,问你A/B的值:注意多项式给你的是每个式子的指数与系数:保留到一位小数,如果出现系数为0(保留后也是)的情况,请不要输出它,如果没有非系数为0的情况就输出特殊 题解:多项式 ...

  9. windchill系统——开发_角色管理——增加角色

    步骤如下 ResourceBuild wt.project.RoleRB ant -f codebase/MakeJar.xml 这样就完成了,接下来看看结果

  10. SVM-支持向量机原理详解与实践

    前言 去年由于工作项目的需要实际运用到了SVM和ANN算法,也就是支持向量机和人工神经网络算法,主要是实现项目中的实时采集图片(工业高速摄像头采集)的图像识别的这一部分功能,虽然几经波折,但是还好最终 ...