語句基礎(chǔ)
-
語句的常見類別
表達(dá)式語句:表達(dá)式后加分號(hào)朴读,對(duì)表達(dá)式求值后丟棄瀑晒,可能產(chǎn)生副作用
空語句:僅包含一個(gè)分號(hào)的語句清蚀,可能與循環(huán)一起工作
-
復(fù)合語句(語句體):由大括號(hào)組成泡孩,無需在結(jié)尾加分號(hào)赚瘦,形成獨(dú)立的域(語句域)
——>更好的控制對(duì)象的生命周期
int main() { // 注意下面實(shí)際上是兩條語句:復(fù)合語句和空語句 {cc // ... }; }
-
順序語句與非順序語句
- 順序語句
- 從語義上安裝先后順序執(zhí)行
- 實(shí)際的執(zhí)行順序可能產(chǎn)生變化(編譯器優(yōu)化粟誓、硬件亂序執(zhí)行)
- 與硬件流水線緊密結(jié)合,執(zhí)行效率較高
- 非順序執(zhí)行
- 在執(zhí)行過程中引入跳轉(zhuǎn)起意,從而產(chǎn)生復(fù)雜的變化
- 分支預(yù)測錯(cuò)誤可能導(dǎo)致執(zhí)行性能降低
- 順序語句
-
最基本的非順序語句:
goto
#include <iostream> int main() { int x = 3; if (x) goto label; x = x + 1; label: return 0; }
- 通過標(biāo)簽指定跳轉(zhuǎn)到的位置
- 具有若干限制
- 不能跨函數(shù)跳轉(zhuǎn)
- 向前跳轉(zhuǎn)時(shí)不能越過對(duì)象初始化語句
- 向后跳轉(zhuǎn)可能會(huì)導(dǎo)致對(duì)象銷毀與重新初始化
-
goto
本質(zhì)上對(duì)應(yīng)了匯編語言中的跳轉(zhuǎn)指令- 缺乏結(jié)構(gòu)性的含義
- 容易造成邏輯混亂
- 除特殊情況外鹰服,應(yīng)避免使用
分支語句
if
使用語句塊表示復(fù)雜的分支邏輯
-
從
if
到if-else
- 實(shí)現(xiàn)多重分支
-
else
會(huì)與最近的if
匹配 - 使用大括號(hào)改變匹配規(guī)則
// 一個(gè)不合原意的應(yīng)用
// grade > 80 --> Excellent
// grade <= 60 --> Bad
int grade = 65;
if (grade > 60)
if (grade > 80)
std::cout << "Excellent\n";
else
std::cout << "Bad\n";
-
if
V.S.constexpr if
—— 運(yùn)行期與編譯器分支
constexpr int grade = 80;
if constexpr (grade < 60)
{
//...
}
- 帶初始化的
if
int x = 3;
// y的作用域?yàn)閕f-else語句范圍內(nèi)
if (int y = x * 3; y > 100)
{
std::cout << y << '\n';
}
else
{
std::cout << -y << '\n';
}
switch
- 語法:https://zh.cppreference.com/w/cpp/language/switch
- 條件部分應(yīng)當(dāng)能夠隱式轉(zhuǎn)換為整型或枚舉類型,可以包含初始化的語句
-
case
/default
標(biāo)簽-
case
后面跟常量表達(dá)式(即在編譯期可以求值的式子)揽咕,用于匹配switch
中的條件悲酷,匹配時(shí)執(zhí)行后續(xù)的代碼 - 可以使用
break
跳出當(dāng)前的switch
執(zhí)行 -
default
用于定義缺省情況下的邏輯 - 在
case
/default
中定義對(duì)象要加大括號(hào)
-
int x;
switch (std::cin >> x; x)
{
case 3:
std::cout << "Hello\n"; // fall through
case 4:
std::cout << "World\n";
}
-
[[fallthrough]]
屬性
int x;
switch (std::cin >> x; x)
{
case 3:
std::cout << "Hello\n";
[[fallthrough]];
case 4:
std::cout << "World\n";
}
- 與
if
相比的優(yōu)劣- 分支描述能力較弱
- 在一些情況下能引入更好的優(yōu)化
循環(huán)語句
while
- 語法:https://zh.cppreference.com/w/cpp/language/while
- 處理邏輯:
- 判斷條件是否滿足,如果不滿足則跳出循環(huán)
- 如果條件滿足則執(zhí)行循環(huán)體
- 執(zhí)行完循環(huán)體后轉(zhuǎn)向步驟1
- 注意:在
while
的條件部分不包含額外的初始化內(nèi)容
do-while
- 語法:https://zh.cppreference.com/w/cpp/language/do
- 注意結(jié)尾處要有分號(hào)亲善,表示一條語句的結(jié)束
- 處理邏輯:
- 執(zhí)行循環(huán)體
- 斷條件是否滿足设易,如果不滿足則跳出循環(huán)
- 如果條件滿足則轉(zhuǎn)向步驟1
- 注:
do-while
中條件處不支持帶花括號(hào)或等號(hào)初始化器的單個(gè)變量的聲明。
// 錯(cuò)誤的語句
do
{
// ...
} while (int x = 0);
for
-
處理邏輯:
- 初始化語句會(huì)被首先執(zhí)行
- 條件部分會(huì)被執(zhí)行蛹头,執(zhí)行結(jié)果如果為
false
顿肺,則終止循環(huán) - 否則執(zhí)行循環(huán)體
- 迭代表達(dá)式會(huì)被求值,之后轉(zhuǎn)向2
在初始化語句中聲明多個(gè)名字
for (int i = 0, *p = &i; i < 9; i += 2)
{
std::cout << i << ' : ' << *p << ' ';
}
std::cout << '\n';
- 初始化語句渣蜗、條件屠尊、迭代表達(dá)式可以為空
- 條件若為空語句則系統(tǒng)默認(rèn)為
TRUE
- 條件若為空語句則系統(tǒng)默認(rèn)為
-
for
的更多示例
基于范圍的for
循環(huán)
- 語法:https://zh.cppreference.com/w/cpp/language/range-for
- 本質(zhì):語法糖,編譯器會(huì)轉(zhuǎn)換為
for
循環(huán)的調(diào)用方式 - 轉(zhuǎn)換形式的衍化:C++11/C++17/C++20
- 使用常量左值引用讀元素袍睡;使用“萬能引用(universal reference)-> auto &&”修改元素
{
// C++17標(biāo)準(zhǔn)
auto && __range = 范圍表達(dá)式;
for (auto __begin = 首表達(dá)式, __end = 尾表達(dá)式; __begin != __end; ++__begin)
{
范圍聲明 = *__begin;
// 循環(huán)語句...
}
}
std::vector<std::string> arr{"h", "e", "l"};
for (const std::string & v : arr)
std::cout << v << '\n';
break
/continue
- 含義(轉(zhuǎn)自cpp reference)
-
break
:導(dǎo)致外圍的for
知染、范圍for
、while
或do-while
循環(huán)或switch
語句終止 -
continue
:用于跳過整個(gè)for
斑胜、while
或do-while
循環(huán)體的剩余部分
-
- 注意這二者均不能用于多重嵌套循環(huán)控淡,多重嵌套循環(huán)的跳轉(zhuǎn)可以考慮
goto
語句
語句的綜合應(yīng)用——達(dá)夫設(shè)備
- 使用循環(huán)展開提升系統(tǒng)性能
- 處理無法整除的情形
- 額外增加一個(gè)循環(huán)語句 ——> 循環(huán)展開
- 將switch與循環(huán)結(jié)合——達(dá)夫設(shè)備
#include <iostream>
#include <vector>
int main (void)
{
constexpr size_t buffer_count = 10000;
std::vector<size_t> buffer(buffer_count);
for (size_t i = 0; i < buffer_count; ++i)
{
buffer[i] = i;
}
size_t max_value = buffer[0];
auto ptr = buffer.begin();
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;
}
for (size_t i = buffer_count / 8 * 8; i < buffer_count; ++i)
{
max_value = (max_value > buffer[i]) ? max_value : buffer[i] ;
}
std::cout << max_value << '\n';
}
#include <iostream>
#include <vector>
int main (void)
{
constexpr size_t buffer_count = 10000;
std::vector<size_t> buffer(buffer_count);
for (size_t i = 0; i < buffer_count; ++i)
{
buffer[i] = i;
}
size_t max_value = buffer[0];
auto ptr = buffer.begin();
size_t i = 0;
switch (buffer_count % 8) {
for (; i < (buffer_count + 7) / 8; ++i) {
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;
}
}
std::cout << max_value << '\n';
}
```cc