语句
语句基础
常见类别
表达式语句:表达式后加分号
表达式求值,后丢弃
可能产生副作用
2 + 3; //表达式;
int x;
x = 3; //表达式求值,返回值x后丢弃
//副作用:x值的改变
空语句:仅包含一个分号的语句
常用在循环体
复合语句(语句体):{ ......} 结尾无分号
{
int x = 3;
x+=1;
std::cout << x << "\n";
} //一条复合语句
//形成独立的域(语句域)
//域中可定义临时变量,精确控制生命周期
{
...
};//两条语句 ;为空语句
int x = 2;
{
int x = 3;
x++;
}
顺序语句与非顺序语句
顺序语句
语义上按照先后顺序执行
实际的执行顺序可能产生变化,编译器优化/硬件乱序执行等
与硬件流水线紧密结合,执行效率较高
非顺序语句
在执行过程中引入跳转,产生复杂变化
分支预测提升性能,预测错误可能导致执行性能降低
会限制编译器优化
goto
通过标签指定跳转位置
限制:
不能跨函数跳转
向前(下)跳转时,不能越过初始化语句
向后跳转可能导致对象的销毁与重新初始化
goto本质对应汇编中的跳转指令
缺乏结构性的含义
容易造成逻辑混乱
避免使用
int main()
{
int x = 1;
if(x) goto label;
x++;
label:
return 0'
}
分支语句
非顺序语句分为分支语句与循环语句
if 与 switch
if
if (){ } else { } 双分支
if (){ } else { if (){ } else{ } }多分支
if (){ } else if (){ } else{ } 省去大括号 等价
else会与最近的if进行匹配
int grade = 65;
if (grade > 60)
if(grade >80)
std::cout << "Excellent\n";
else //缩进无效,与第二个if匹配
std::cout <<"Bad\n";
使用大括号明确 避免匹配错误,
constexpr if
c++17 开始可加入 constexpr
编译期优化
constexpr int grade = 59;
if constexpr(grade <60)
{
std:cout <<"fail \n";
}
else
{
std::cout <<"pass\n";
if constexpr (grade == 100)
{
std::cout << "excellent \n";
}
else
{
std::cout << "not bad \n";
}
}
带初始化语句的if (c++17)
int x = 3;
if(int y = x*3; y>100) //y作用域到else结束
{
//......
}
else
{
//......
}
switch
条件:任何整型或枚举类型,或可按语境隐式转换到整型或枚举类型的表达式
语句:任何语句。 case: default: break;
case/default 标签
case:跟常量表达式,匹配switch中条件,匹配执行后续
break: 避免fall through
-Wimplicit-fallthrough 产生编译警告
default: 位置任意,放前边注意加break
int x ;
switch(std::cin >> x; x)//可选初始化 (c++17)
{
case 2+1:
std::cout<<"3\n";
break;
}
case/default 定义对象必须加{}
case 1:{
int x = 1;
break;
}
共享逻辑
switch(std::cin >> x; x)
{
case 4:
case 5:
//expression
break;
}
[[falthrough]]属性 (c++17)
switch (x)
{
case 1:
//......
[[fallthrough]];//表明确实不需要break;
case 2:
//......
break;
}
switch与if对比
switch能做的if都可以,反之不一定
switch一定程度上可在通过跳转进行优化,运行期效率比if更高
循环语句
对一系列语句反复执行
while/do while
条件:任何能按语境转换为bool的表达式,
或带花括号或等号初始化器的单个变量的声明
语句:任何语句,它是循环体
while(int x = 3)//等号初始化器,返回3
//每次循环都会初始化
{
std::cout << x << std::endl;
--x;
}
不包含额外的初始化内容(for循环包含初始化,不会重复初始化)
do while
条件:不能带花括号或等号初始化表达式(do未初始化)
结尾加分号
for
正式语法:
attr(可选) for( 初始化语句 条件(可选);迭代表达式(可选))语句
非正式语法:
attr(可选) for(声明或表达式(可选); 声明或表达式(可选);表达式(可选))语句
初始化语句: 一条表达式语句(可为空 ;)
一条简单声明,通常为带初始化器的循环计数变量的声明,可以任意多个变量
条件: 可按语境转换到bool的表达式。每次循环 之前 重复求值
迭代表达式: 任何表达式。每次循环 之后 重复求值,通常为循环计数器表达式
语句: 任何语句。作为循环体
for(int i = 0, *p = &i;i < 9; i+=2) //可以声明多个名字
//只要它们能用拥有相同的声明说明符序列
//基础类型不能改变
{
std::cout < v = {3,1,4,1,5,9};
for(auto iter = v.begin();iter != v.end();++iter)
{}
//=======================================================
//非典型使用
int n = 0;
for(std::cout << "循环开始\n";
std::cout << "循环测试\n"; //输出正常返回true
std::cout << "迭代" << ++n << '\n')
if(n>1)
break;
/*
循环开始
循环测试
迭代1
循环测试
迭代2
循环测试
*/
基于范围的for循环(range for loop)
C++11/17/20
语法: 属性(可选) for(范围声明:范围表达式)循环语句
属性(可选) for(初始化语句(可选)范围声明:范围表达式)循环语句 --c++20
本质: 语法糖,编译器转换为for循环形式
int main()
{
std::vector arr{1,2,3,4,5};
for(int v : arr)
std::cout << v << '\n';
}
range for 不同版本转换/解释
{
auto && __range = range-expression ;//范围表达式
for (auto __begin = begin_expr, __end = end_expr;//首表达式,尾表达式
__begin != __end; ++__begin) {
range-declaration = *__begin;//范围声明
loop-statement //循环语句
}
}
(until C++17)
//=================================================================
{ //首表达式,尾表达式可能返回不同类型,c++17通过分开声明解决
auto && __range = range-expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range-declaration = *__begin;
loop-statement
}
}
(since C++17)
(until C++20)
//=================================================================
{ //c++20引入初始化语句,解决临时范围表达式问题
init-statement
auto && __range = range-expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range-declaration = *__begin;
loop-statement
}
}
(since C++20)
//=================================================================
//临时范围表达式
for(auto& x : foo().items()){ /*......*/}//行为可能不确定
//若foo返回右值,可能被销毁,x引用绑定失效,循环产生未定义的行为
//c++20引入初始化语句解决
for(T thing = foo();auto& x : thing.items()){/*......*/}
//foo()产生的右值被保留到thing中,thing生命周期到循环结束
使用常量左值引用读元素
使用“万能引用(universal reference)”修改元素
std::vector arr{"h","e","l","l","o"};
for (const std::string& v : arr)//使用常量左值引用,避免重新构造string,更高效
//const auto& v : arr
std::cout << v << '\n';
std::vector arr1{true,false,true};
for(auto& v : arr1) {} //error bool迭代器解引用不是bool
for(auto&& v : arr1) {} //万能引用
break/continue
break:
continue:
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 5; k++) { // break 只会影响此循环
if (k == 2) break;
std::cout << j << k << " ";
}
}
//00 01 10 11
for (int i = 0; i < 10; i++) {
if (i != 5) continue;
std::cout << i << " "; // 每次 i!=5 时跳过此语句
}
std::cout << '\n';
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 5; k++) { // continue 只会影响此循环
if (k == 3) continue;
std::cout << j << k << " "; // 每次 k==3 时跳过此语句
}
}
break;continue;不能用于多重嵌套循环
多重嵌套循环跳转考虑使用goto
for(int j = 0; j < 2; j++){
for(int k = 0;k < 5;k++){
if(k == 2) goto label;
std::cout << j << k << " ";
}
}
label:
//......
达夫设备
constexpr size_t buffer_count = 10000;
std::vector buffer(buffer_count);
for(size_t i = 0;i< buffer_count;++i)
{buffer[i] = i;}
size_t max_value = buffer[0];
for(size_t i = 0; i < buffer_count; ++i)//花费成本更多
{
max_vlaue = (max_value > buffer[i]) ? max_value : buffer[i];
}
std::cout << max_vlaue << "\n";
//==============================================================
//循环展开
for(size_t i = 0; i + 8 < buffer_count; i+=8)//循环处理减少,程序性能提升
{
max_vlaue = (max_value > buffer[i]) ? max_value : buffer[i];
max_vlaue = (max_value > buffer[i+1]) ? max_value : buffer[i+1];
max_vlaue = (max_value > buffer[i+2]) ? max_value : buffer[i+2];
max_vlaue = (max_value > buffer[i+3]) ? max_value : buffer[i+3];
max_vlaue = (max_value > buffer[i+4]) ? max_value : buffer[i+4];
max_vlaue = (max_value > buffer[i+5]) ? max_value : buffer[i+5];
max_vlaue = (max_value > buffer[i+6]) ? max_value : buffer[i+6];
max_vlaue = (max_value > buffer[i+7]) ? max_value : buffer[i+7];
}
//但是内存访问越界
//处理剩余
for(size_t i = buffer_count / 8 *8;i< buffer_count;++i)
{
max_vlaue = (max_value > buffer[i]) ? max_value : buffer[i];
}
//=======================================================================
//指针优化,switch优化
auto ptr = buffer.begin();
for(size_t i = 0; i + 8 < buffer_count; i+=8)
{
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
}
switch(buffer_count % 8)
{
case 7:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 6:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 5:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 4:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 3:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 2:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 1:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
}
//====================================================================
//继续优化
switch(buffer_count % 8)
{
case 0:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 7:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 6:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 5:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 4:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 3:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 2:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]]
case 1:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
}
for(size_t i = 0; i < (buffer_count-1)/8; ++i)
{
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
}
//====================================================================
//达夫设备 switch 套循环
size_t i = 0;
switch(buffer_count % 8)
for(;i<(buffer_count+7)/8;++i)
{
[[fallthrough]];
case 0:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]];
case 7:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]];
case 6:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]];
case 5:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]];
case 4:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]];
case 3:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]];
case 2:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;[[fallthrough]];
case 1:max_value = (max_value > *ptr) ? max_value : *ptr; ++ptr;
}
//直接跳转到for内部,再触发循环