Chapter 5 语句
语句基础
- 常见类别
- 表达式语句:表达式后加分号,对表达式求值后丢弃,可能产生副作用
- 空语句:仅包含一个分号的语句,可能与循环一起工作
- 符合语句(语句体):由大括号组成,无需在结尾加分号,形成独立的域(语句域)
- 顺序语句与非顺序语句
- 顺序语句
- 从语义上按照先后顺序执行
- 实际的而执行顺序可能产生变化(编译器优化、硬件乱序执行)
- 与硬件流水线紧密结合,执行效率较高
- 非顺序语句
- 在执行过程中引入跳转,从而产生复杂的变化
- 分支预测错误可能导致执行性能降低
- 顺序语句
- 最基本的非顺序语句:
goto
- 通过标签指定跳转到的位置
- 具有若干限制
- 不能跨函数跳转
- 向前跳转时不能越过对象初始化语句
- 向后跳转可能会导致对象销毁与重新初始化
- goto本质上对应了汇编语言的跳转指令
- 缺乏结构性的含义
- 容易造成逻辑混乱
- 除特殊情况外,应避免使用
分支语句——if
语法
1
2
3
4
5
6if(条件){
}
else if{
}
else{
}使用语句块表示复杂的分支逻辑
从if到if-else
- 实现多重分支
- else会与最近的if匹配,可以使用大括号改变匹配规则
- 不能通过缩进和换行改变匹配规则
if
vsconstexpr if
——运行期与编译期分支
1 | if constexpr (A>5){ |
- 带初始化语句的if
1 | if (int y = X * 3; y > 100)//初始化y,if执行完之后y就销毁了,外部可重新定义y |
分支语句——switch
语法
1
2switch (条件) 语句
//执行对应case之后的代码,后续的case也会执行!使用break跳出!!!条件部分应当能够隐式转换为整形或枚举类型,可以包含初始化的语句
1 | int x; |
- case/default 标签
- case后面跟常量表达式,用于匹配switch中的条件,匹配时执行后续的代码
- 可以使用break跳出当前的switch执行
- default用于定义缺省情况下的逻辑
- 在case/default中定义对象要加大括号
[[fallthrough]];
属性,允许此处不加break,不会报警告- 与if相比的优劣势
- 分支描述能力较弱
- 在一些情况下能引入更好的优化,运行期节省时间
循环语句——while
语法
1
2
3while(x>3){
...
}处理逻辑
- 判断条件是否满足,如果不满足则跳出循环
- 如果条件满足则执行循环体
- 执行完循环体后转向步骤1
注意:在while的条件部分不包含额外的初始化内容
循环语句——do while
- 语法
1 | do 语句 while(表达式);//表达式部分不能加初始化 |
- 注意结尾需要加分号,表示一条语句的结束
- 处理逻辑
- 执行循环体
- 判断条件是否满足,如果不满足则跳出循环
- 如果条件满足则转向步骤1
循环语句——for
- 语法
1 | for (初始化语句 条件(可选); 迭代表达式(可选)) 语句 // 正式 |
- 处理逻辑
- 初始化语句会被首先执行
- 条件部分会被执行,执行结果如果为false,则终止循环
- 否则执行循环体
- 迭代表达式会被求值,之后转向2
- 在初始化语句中声明多个名字
- 初始化语句、条件、迭代表达式可以为空
- for的更多示例
循环语句——基于范围的for循环
- 语法
1 | for (范围声明; 范围表达式) 循环语句 |
- 本质:语法糖,编译器会转换为for循环的调用方式
1 | vector<int> arr{1,2,3,4,5}; |
- 转换形式的演化:C++11/C++17/C++20
- 使用常量左值引用读元素;使用“万能引用”修改元素(
auto &&
万能引用)
循环语句——break/continue
- 含义
- break:导致外围的for、范围for、while或do-while循环或switch语句终止
- continue:用于跳过整个for、while或do-while 循环体的剩余部分
- 注意这两者均不能用于多重嵌套循环,多重嵌套循环的跳转可考虑goto语句
语句的综合应用——达夫设备
switch里面嵌套循环体的结构称为达夫设备
使用循环展开提升系统性能
- 把循环内部变复杂,减少循环执行次数。当心内存访问越界
处理无法整除的情形
- 额外增加一个循环语句
- 将switch与循环结合——达夫设备