读书心得(表达式与基本语句篇)

news2024/12/25 10:01:32

 内容取自《高质量C/C++编程指南》

         读者可能怀疑:连 if、for、while、goto、switch 这样简单的东西也要探讨编程风格,是不是小题大做?我真的发觉很多程序员用隐含错误的方式写表达式和基本语句,我自己也犯过类似的错误。表达式和语句都属于 C++/C 的短语结构语法。它们看似简单,但使用时隐患比较多。本章归纳了正确使用表达式和语句的一些规则与建议。

一、 运算符的优先级

         这里要注意一元运算符 + - * 的优先级高于对应的二元运算符。

规则:如果代码行中的运算符比较多,用括号确定表达式的操作顺序,避免使用默认的优先级。

        由于将表 4-1 熟记是比较困难的,为了防止产生歧义并提高可读性,应当用括号确
定表达式的操作顺序。例如:  if ((a | b) && (a & c))

二、 复合表达式

        如 a = b = c = 0 这样的表达式称为复合表达式。允许复合表达式存在的理由是:(1)书写简洁;(2)可以提高编译效率。但要防止滥用复合表达式。

规则:

1、不要编写太复杂的复合表达式。如:

i = a >= b && c < d && c + f <= g + h ;    // 复合表达式过于复杂

2、不要有多用途的复合表达式。如:

d = (a = b + c) + r ;
该表达式既求 a 值又求 d 值。应该拆分为两个独立的语句:
a = b + c;
d = a + r;

3、不要把程序中的复合表达式与“真正的数学表达式”混淆。如:

if (a < b < c)         // a < b < c 是数学表达式而不是程序表达式
并不表示    if ((a<b) && (b<c))
而是成了令人费解的    if ( (a<b)<c )

三、 if语句

         if 语句是 C++/C 语言中最简单、最常用的语句,然而很多程序员用隐含错误的方式
写 if 语句。本节以“与零值比较”为例,展开讨论。

 布尔变量与零值比较

规则:不可将布尔变量直接与 TRUEFALSE 或者 10 进行比较。

        根据布尔类型的语义,零值为“假”(记为 FALSE),任何非零值都是“真”(记为TRUE)。TRUE 的值究竟是什么并没有统一的标准。例如 Visual C++ 将 TRUE 定义为1,而 Visual Basic 则将 TRUE 定义为-1。
假设布尔变量名字为 flag,它与零值比较的标准 if 语句如下:
if  (flag)         // 表示 flag 为真
if  (!flag)         // 表示 flag 为假
其它的用法都属于不良风格,如:
if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)

 整型变量与零值比较

规则:应当将整型变量用“==”或“!=”直接与 0 比较。

假设整型变量的名字为 value,它与零值比较的标准 if 语句如下:
if (value == 0)
if (value != 0)
不可模仿布尔变量的风格 而写成
if (value)                // 会让人误解 value 是布尔变量
if (!value)

浮点变量与零值比较 

规则:不可将浮点变量用“==”或“!=”与任何数字比较。
         千万要留意,无论是 float 还是 double 类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。
假设浮点变量的名字为 x,应当将 if (x == 0.0)         // 隐含错误的比较
转化为 if ((x>=-EPSINON) && (x<=EPSINON)), 其中 EPSINON 是允许的误差(即精度)。

指针变量与零值比较  

规则:应当将指针变量用“==”或“!=”与 NULL 比较。
         指针变量的零值是“空”(记为 NULL)。尽管 NULL 的值与 0 相同,但是两者意义不
同。假设指针变量的名字为 p,它与零值比较的标准 if 语句如下:
if (p == NULL)         // p 与 NULL 显式比较,强调 p 是指针变量
if (p != NULL)
不要写成
if (p == 0) // 容易让人误解 p 是整型变量
if (p != 0)
或者
if (p) // 容易让人误解 p 是布尔变量
if (!p)

对 if 语句的补充说明 

        1、有时候我们可能会看到 if (NULL == p) 这样古怪的格式。不是程序写错了,是程
序员为了防止将 if (p == NULL) 误写成 if (p = NULL),而有意把 p 和 NULL 颠倒。
编译器认为 if (p = NULL) 是合法的,但是会指出 if (NULL = p)是错误的,因为 NULL
不能被赋值。
2、程序中有时会遇到 if/else/return 的组合,应该将如下不良风格的程序
if (condition)
return x;
return y;
改写为
if (condition)
{
return x;
}
else
{
return y;
}
或者改写成更加简练的
return (condition ? x : y);

四、循环语句的效率

        C++/C 循环语句中,for 语句使用频率最高,while 语句其次,do 语句很少用。本节重点论述循环体的效率。提高循环体效率的基本办法是降低循环体的复杂性。

建议:

1、在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少 CPU 跨切循环层的次数。例如:

        示例 4-4(b)的效率比示例4-4(a)的高。

2、如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。例如:

        示例 4-4(c)的程序比示例 4-4(d)多执行了 N-1 次逻辑判断。并且 由于前者老要进行逻辑判断,打断了循环“流水线”作业,使得编译器不能对循环 进行优化处理,降低了效率。如果 N 非常大,最好采用示例 4-4(d)的写法,可以提 高效率。如果 N 非常小,两者效率差别并不明显,采用示例 4-4(c)的写法比较好, 因为程序更加简洁。

五、for 语句的循环控制变量

规则:不可在 for 循环体内修改循环变量,防止 for 循环失去控制。
建议:建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法。
        示例 4-5(a)中的 x 值属于半开半闭区间“0 =< x < N”,起点到终点的间隔为 N, 循环次数为 N。 示例 4-5(b)中的 x 值属于闭区间“0 =< x <= N-1”,起点到终点的间隔为 N-1,循 环次数为 N。
相比之下,示例 4-5(a)的写法更加直观,尽管两者的功能是相同的。

六、switch 语句

        很多人都会有一个想法:既然已经有 if 语句了,为什么还要 使用switch语句呢?在本书中给出了相应的回答:switch 是多分支选择语句,而 if 语句只有两个分支可供选择。虽然可以用嵌套的 if 语句来实现多分支选择,但那样的程序冗长难读。这是 switch 语句存在的理由。

switch 语句的基本格式是:
switch (variable)
{
        case value1 : …
        break;
        case value2 : …
        break;
        …
        default : …
        break;
}
规则:
1、每个 case 语句的结尾不要忘了加 break,否则将导致多个分支重叠 (除非有意使多个分支重叠)。
2、 不要忘记最后那个 default 分支。即使程序真的不需要 default 处理, 也应该保留语句 default : break; 这样做并非多此一举,而是为了防止别人误以 为你忘了 default 处理。

 

七、goto语句

 

         自从提倡结构化设计以来,goto 就成了有争议的语句。首先,由于 goto 语句可以
灵活跳转,如果不加限制,它的确会破坏结构化设计风格。其次,goto 语句经常带来错
误或隐患。它可能跳过了某些对象的构造、变量的初始化、重要的计算等语句,例如:
goto state;
String s1, s2; // 被 goto 跳过
int sum = 0; // 被 goto 跳过
state:
如果编译器不能发觉此类错误,每用一次 goto 语句都可能留下隐患。
        很多人建议废除 C++/C 的 goto 语句,以绝后患。但实事求是地说,错误是程序员
自己造成的,不是 goto 的过错。goto 语句至少有一处可显神通,它能从多重循环体中
咻地一下子跳到外面,用不着写很多次的 break 语句; 例如
{ …
        { …
                { …
                        goto error;
                }
        }
}
error:
        就像楼房着火了,来不及从楼梯一级一级往下走,可从窗口跳出火坑。所以我们主张少用、慎用 goto 语句,而不是禁用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1321782.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

共同编辑文档功能实现(websocket)

目录 前言 websocket封装 wangeditor下载 共同编辑文档代码实现 HTML样式部分 JS部分 css部分 前言 功能&#xff1a;实现文档共同编辑功能&#xff0c;可以实时接收到其他人的信息 思路&#xff1a;先调用接口获取相应的数据进行渲染&#xff0c;然后通过webSocket建…

Adaptive IBC :异构链互操作性的颠覆者

2024年第一季度&#xff0c;隐私协议 Secret Network 将会使用 Octopus Network 基于 Adaptive IBC 技术路线开发的 NEAR IBC&#xff0c;实现与 NEAR Protocol 之间将会实现首次跨链交互&#xff0c;这同样是 Cosmos 生态与 NEAR 之间的首次连接。整个加密世界正在成为一个越来…

19 高速列车场景下3Gpp 5G NR的DMRS设计与评估

文章目录 解决问题设计DMRS仿真参数仿真结果 解决问题 多普勒/扩展影响十分显著&#xff0c;设计用于信道估计时&#xff0c;需要考虑解调参考信号&#xff0c;5G用DMRS结构而不是CRS结构&#xff0c;因此需要为高速UE设计DMRS结构&#xff0c;DMRS设计是为了提高信道估计并减…

JVM-1-运行时数据区

程序计数器&#xff08;Program Counter Register&#xff09; 是一块较小的内存空间&#xff0c;它可以看作是当前线程所执行的字节码的行号指示器。在Java虚拟机的概念模型里[1]&#xff0c;字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令&…

k8s集群使用calico网络组件

一、前言 k8s的网络组件可以使用flannel或者calico两种&#xff0c;flannel的配置比较简单&#xff0c;但是性能还是calico会更高一点&#xff0c;所以现在来介绍以下calico网络组件的部署 二、部署 k8s集群版本对calico的版本也有对应要求&#xff0c;k8s 1.23.0版本要求对应…

Android13音频录制适配

Android13音频录制适配 前言&#xff1a; 之前写过一篇音频录制的文章&#xff0c;当时是在Android10以下的手机可以成功录制和播放&#xff0c;但是Android10及以上手机提示创建文件失败&#xff0c;最近做过Android13的适配&#xff0c;索性一起把之前的录音也适配了&#…

【MySQL】:表的内外连接

表的内外连接 一.内连接二.外连接1.左外连接2.右外连接 一.内连接 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选&#xff0c;我们前面学习的查询都是内连接&#xff0c;也是在开发过程中使用的最多的连接查询。 语法&#xff1a;select 字段 from 表1 inner …

如何通过浏览器扩展修改浏览器的UserAgent

User-Agent Switcher and Manage&#xff1a; https://chromewebstore.google.com/detail/user-agent-switcher-and-m/bhchdcejhohfmigjafbampogmaanbfkg 使用说明&#xff1a; User Agent Switcher and Manager :: add0n.com 示例&#xff1a; 勾选一个UA&#xff0c;比如c…

测试工具Jmeter:设置中文界面

首先我们打开Jmeter所在的文件&#xff0c;进入bin目录&#xff0c;打开Jmeter.properties&#xff1a; 打开后找到languageen&#xff1a; 改为zh_CN: 保存关闭&#xff0c;然后再打开Jmeter&#xff1a; 英文并不会显得高级&#xff0c;能做到高效的性能测试才是高级的。

邮件营销:定义、优势与策略指南

什么是邮件营销&#xff1f;跨境电商或者出海企业可能会经常使用它&#xff0c;它是传统的营销方式之一&#xff0c;在上世纪80年年代得以运用。 邮件营销&#xff0c;英文全称为Email Direct Marketing&#xff0c;缩写为EDM。它是指在收件人许可的情况下&#xff0c;通过电子…

【经典LeetCode算法题目专栏分类】【第4期】BFS广度优先算法:单词接龙、最小基因变化、二进制矩阵中的最短路径

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 一般涉及到最小层数问题…

用bash写脚本

本章主要介绍如何使用bash写脚本。 了解通配符 了解变量 了解返回值和数值运算 数值的对比 判断语句 循环语句 grep的用法是“grep 关键字 file”&#xff0c;意思是从file中过滤出含有关键字的行。 例如&#xff0c;grep root /var/log/messages&#xff0c;意思是从/var/log/…

家居家纺品牌网站建设的作用是什么

家居家纺企业往往规模很高&#xff0c;比如被褥、枕头床单等都是家家必备的&#xff0c;市场规模连年增长&#xff0c;但在实际经营中&#xff0c;随着互联网深入各个行业&#xff0c;传统企业线上化能力不足&#xff0c;也产生了许多痛点。 1、品牌传播难 家居家纺企业以批发…

PCL点云处理之点云置平(拟合平面绕中心旋转到绝对水平)(二百二十七)

PCL点云处理之点云置平(绕中心旋转到绝对水平)(二百二十七) 一、什么是点云置平二、算法流程三、算法实现一、什么是点云置平 有时候,我们处理的点云平面并非位于水平面,而是位于某个任一三维平面上,而大多数算法又只能在水平面处理,或者水平面的点云处理是相对更简单…

9.鸿蒙app用户界面的跳转abilityslice的跳转

9.用户界面的跳转abilityslice的跳转&#xff0c;值传递&#xff0c;数值累加 首页页面显示1&#xff0c;第2页显示2&#xff0c;再次点击返回首页3。。。 MainAbilitySlice.java 关键代码&#xff1a; 点击事件 text.setClickedListener(new Component.ClickedListener() …

[自动化运维工具]ansible简单介绍和常用模块

ansible 源操作主机功能 自动化运维&#xff08;playbook剧本yaml&#xff09; 是基于python开发的一个配置管理和应用部署工具&#xff0c;在自动化运维中&#xff0c;现在还是异军突起 ansible能批量配置&#xff0c;部署&#xff0c;管理上千台主机&#xff0c;类似于xshell…

安全生产隐患排查治理信息化系统软件

安全隐患排查系统实现对重大危险源企业、安全隐患信息的登记、整改、复查、分类和统计。系统涵盖了安全隐患排查整治工作的各项基本内容&#xff0c;实现以安全隐患排查整治业务流为主线&#xff0c;处理流程简洁清晰、快速灵活&#xff1b;以排查整治流程为干线&#xff0c;快…

5行Python实现验证码识别,太稳了

很久之前&#xff0c;分享过一次Python代码实现验证码识别的办法。 当时采用的是pillowpytesseract&#xff0c;优点是免费&#xff0c;较为易用。但其识别精度一般&#xff0c;若想要更高要求的验证码识别&#xff0c;初学者就只能去选择使用百度API接口了。 但其实百度API接…

Linux-----21、挂载

# 挂载命令 将硬件资源&#xff0c;或文件资源&#x1f4bf;&#xff0c;和&#x1f4c2;空目录&#x1f517;连接起来的过程 # mount linux 所有存储设备都必须挂载使用&#xff0c;包括硬盘 ​ 命令名称&#xff1a;mount ​ 命令所在路径&#xff1a;/bin/mount ​ 执行…

无懈可击的防泄密之旅:迅软DSE在民营银行的成功实践

客户简要介绍 某股份有限公司主体是中部地区的民营银行&#xff0c;由其母公司联合9家知名民营企业共同发起设立。正式开业于2016年&#xff0c;紧紧围绕目标产业生态圈和消费金融&#xff0c;着力打造产业银行、便捷银行、数字银行、财富管理银行为一体的BEST银行&#xff0c…