本文是 本系列的第三篇,本文主要对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. List集合的ForEach扩展

           public static void ForEach<T>(this IEnumerable<T> enumerableSource, Action<T&g ...

  2. cmd 命令 记忆

    1,“开始”—>“运行”,输入cmd,回车.<或 win+R> 2,出现“命令提示符”的窗口,一般情况下是 C:\Documents and Settings\Administrat ...

  3. Java结对编程四则运算一周小结

    Java结对编程四则运算一周小结 需求分析 对于四则运算来说最主要的就是要计算出产生的式子(字符串的形式). 设计思路 总体可将这个项目分解为几个部分:产生式子,计算式子,判断对错并记录: 具体的思路 ...

  4. javascript-电话薄小功能

    上代码: <style> *{ margin:0 ; padding: 0;} .phrase_wrap, .phrase_list{ width: 200px; height: 200p ...

  5. Docker高级使用

    Docker卸载应用程序 先删除容器,在删除镜像 查询容器 docker ps –a 使用容器id删除容器 docker rm 18e672ecd8ed 查询镜像 docker images 使用镜像 ...

  6. JavaScript常用知识点整理——思维导图

    如图 思维导图图片链接 http://www.edrawsoft.cn/viewer/public/s/b8327462051289 有道云笔记图片链接 http://note.youdao.com/ ...

  7. hdu1596 find the safest road - floyd

    2017-08-04 14:42:56 writer:pprp 题意: Problem Description XX星球有很多城市,每个城市之间有一条或多条飞行通道,但是并不是所有的路都是很安全的,每 ...

  8. PHP5+APACHE2.2配置

    注意这里用的是PHP5.3版本 在Windows系统上使用Apache2.2上模块化安装PHP5.3 PHP5.3增加了一些功能,如namespace,静态迟绑定等. 本篇文章将帮您如何安装PHP5. ...

  9. Java条件语句之 if...else

    if...else 语句的操作比 if 语句多了一步:  当条件成立时,则执行 if 部分的代码块: 条件不成立时,则进入 else 部分.例如,如果考试成绩大于 90 分,则奖励一个 IPHONE  ...

  10. T-SQL RIGHT JOIN

    RIGHT JOIN外联接与LEFT JOIN相似.取得右表所有记录,并按过滤条件ON去取得左表的记录,取得这些记录,如遇上没有匹配的列使用NULL填充. 演示数据来源,两张表来自http://www ...