1. 语句的常见类别:

表达式语句:表达式后加分号,对表达式求值后丢弃,可能产生副作用
空语句:仅包含一个分号的语句,可能与循环一起工作
复合语句(语句体):由大括号组成,无需在结尾加分号,形成独立的域(语句域)

2. 顺序语句与非顺序语句:

2.1 顺序语句

从语义上按照先后顺序执行
实际的执行顺序可能产生变化(编译器优化、硬件乱序执行)
与硬件流水线紧密结合,执行效率较高

2.2 非顺序语句

在执行过程中引入跳转,从而产生复杂的变化
分支预测错误可能导致执行性能降低

2.3 最基本的非顺序语句: goto

2.3.1 通过标签指定跳转到的位置,具有若干限制

不能跨函数跳转

  1. #include <iostream>
  2. void fun()
  3. {
  4. goto label;
  5. }
  6. int main()
  7. {
  8. fun();
  9. label:
  10. std::cout << "hello world" << std::endl;
  11. }

这段代码会报错:

  1. error:Use of undeclared label 'label'

向前跳转时不能越过对象初始化语句

  1. #include <iostream>
  2. int main()
  3. {
  4. int x = 5;
  5. goto end; // 错误:goto语句绕过了一个带初始化的变量定义
  6. int y = 5;
  7. end:
  8. // 显然goto语句跳过了y的声明
  9. y = 6;
  10. }

问题描述:

  1. Cannot jump from this goto statement to its label

向后跳转可能会导致对象销毁与重新初始化

  1. // 向后跳过一个带初始化的变量定义是合法的
  2. begin:
  3. int sz = get_size();
  4. if(sz <= 0){
  5. goto begin;
  6. }

跳回到变量定义之前意味着系统将摧毁该变量并重新创建它

2.3.2 goto 本质上对应了汇编语言中的跳转指令

缺乏结构性的含义
容易造成逻辑混乱
除特殊情况外,应避免使用

2.4 if-statement

2.4.1 else 会与最近的 if 匹配 —— 使用大括号改变匹配规则

2.4.2 if vs constexpr if

2.4.3 带初始化语句的 if (C++17起)

2.5 switch-statement

条件部分应当能够隐式转换为整形或枚举类型,可以包含初始化的语句

2.5.1 case/default 标签

case 后面跟常量表达式 , 用于匹配 switch 中的条件,匹配时执行后续的代码
可以使用 break 跳出当前的 switch 执行
default 用于定义缺省情况下的逻辑
在 case/default 中定义对象要加大括号

2.5.2 [[fallthrough]] 属性

2.5.3 与 if 相比的优劣

分支描述能力较弱
在一些情况下能引入更好的优化