C语言KR圣经笔记 2.11条件表达式 2.12优先级和求值顺序

本文主要是介绍C语言KR圣经笔记 2.11条件表达式 2.12优先级和求值顺序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2.11条件表达式

 if (a > b) z = a; else z = b; 

上面的语句计算 a 和 b 中的最大值并存入 z。而使用三元操作符 ? :  条件表达式,为这个结构及类似结构提供了另一种写法。在如下表达式

expr1 ? expr2 : expr3

中,首先对 expr1 求值。如果值非0 (为真),则对 expr2 求值,而得到的也是整个条件表达式的值。若 exp1 的值为0(为假),则对 expr3 求值,得到整个表达式的值。 expr2 和 expr3 中只会有一个表达式被求值。因此,把 z 设为 a 和 b 的最大值就能写成:

z = a > b ? a : b;    /* z = max(a,b) */

需要注意,条件表达式确实是一个表达式,它能出现在任何其他表达式可以出现的地方。如果 expr2 和 expr3 的类型不同,则结果的类型取决于本章前面讨论过的转换规则。例如, 如果 f 是 float 而 n 是 int,则表达式

(n > 0) ? f : n

的类型是 float, 不管 n 是否大于 0。

条件表达式的第一个表达式两边不用加上括号,因为 ?: 的优先级非常低,仅高于赋值。然而加上括号是明智的,因为这会让条件表达式的条件部分看起来更明显。

条件表达式可以带来更简洁的代码。例如,下面这个循环会打印数组的 n 个元素,每行10个,中间用空格隔开,每行(包括最后一行)末尾以换行符结束。

for (i = 0; i < n; ++i)printf("%6d%c", a[i], (i%10==9 || i== n-1) ? '\n' : ' ');

每10个元素后面打印一个换行符,第n个元素后面也要。其他所有元素后面打印空格。代码可能看起来有点绕,但比对应的 if-else 写法要紧凑。还有个不错的例子是

printf("You have %d items%s.\n", n, n==1 ? "" : "s"); 

练习2-10、重写 把大写字母转小写的 lower 函数,用条件表达式,不用 if-else。

2.12优先级和求值顺序

表2-1总结了所有操作符的优先级和结合性,包括那些我们还没讲到的。同一行的操作符有相同的优先级;行按优先级降序排列,例如 操作符 * / % 的优先级相同,而它们三个的优先级都比二元操作符 + -  要高。括号“操作符” ( ) 指的是函数调用。操作符 -> 和 . 用来访问结构的成员,还有 sizeof(对象的大小),都会在第6章讲到。第5章会讨论  * (通过指针引用)和 & (对象的地址),而第3章会讨论逗号操作符。

注意位操作符 & ^ | 优先级低于 == 和 !=。这隐含说明,用来测试位的表达式如

if ((x & MASK) == 0) ...

里面必须全部用括号包起来,才能得到想要的结果。

C,和大多数语言一样,并没有指定一个操作符中多个操作数的求值顺序。(操作符  && || ?: 和逗号操作符除外)。例如语句

x = f() + g()

f 可能 在 g 之前求值,可能相反;这样如果 f 或 g 改变了对方依赖的一个变量值,则 x 的值依赖于求值顺序。应对这种情况,可以用临时变量来保存中间结果,以保证所需的顺序。

类似的,函数的多个参数的求值顺序也是没有规定的,因此语句

printf("%d %d\n", ++n, power(2,n));    /* WRONG */

用不同的编译器可以产生不同的结果,依赖于 n 是否在 power 被调用之前自增。当然,解决方法是写成

++n;
printf("%d %d\n", n, power(2,n));

函数调用,嵌套的赋值语句,以及自增和自减操作符,都会带来“副作用”——作为表达式求值的副产品,某些变量被改变了。在任何涉及副作用的表达式中,都可能存在对表达式中变量的更新顺序的微妙依赖。这种代码令人难受。来看一个典型的:

a[i] = i++;

问题是,数组下标用的是 i 的老值还是新值?不同的编译器可以用不同的方式来解释,并基于不同的解释生成不同的结果。标准有意地不明确规定大部分的这类问题。表达式中的副作用(对变量赋值)何时发生,这个决定权交给了编译器,因为最佳的选择强烈依赖于机器架构。(标准的确规定了,所有参数的副作用生效在函数被调用之前,但这无法解决上面的 printf 问题。)

结论就是:不管在任何语言中,写出依赖于求值顺序的代码都是糟糕的编程实践。自然地,有必要知道应该避免什么,但如果你不知道在各种不同的机器上是分别如何实现的,你也不会忍不住去利用某种特定的实现。

(第二章完)

这篇关于C语言KR圣经笔记 2.11条件表达式 2.12优先级和求值顺序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/321800

相关文章

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

Spring如何使用注解@DependsOn控制Bean加载顺序

《Spring如何使用注解@DependsOn控制Bean加载顺序》:本文主要介绍Spring如何使用注解@DependsOn控制Bean加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录1.javascript 前言2. 代码实现总结1. 前言默认情况下,Spring加载Bean的顺

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

Go语言中Recover机制的使用

《Go语言中Recover机制的使用》Go语言的recover机制通过defer函数捕获panic,实现异常恢复与程序稳定性,具有一定的参考价值,感兴趣的可以了解一下... 目录引言Recover 的基本概念基本代码示例简单的 Recover 示例嵌套函数中的 Recover项目场景中的应用Web 服务器中

Java中JSON格式反序列化为Map且保证存取顺序一致的问题

《Java中JSON格式反序列化为Map且保证存取顺序一致的问题》:本文主要介绍Java中JSON格式反序列化为Map且保证存取顺序一致的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录背景问题解决方法总结背景做项目涉及两个微服务之间传数据时,需要提供方将Map类型的数据序列化为co