代碼優化應在「功能正確」後進行。本文整理 30 條 C/C++ 低層優化建議,涵蓋分支、內存訪問、函數調用、數據結構、編譯器協作等維度,適合高性能計算、遊戲引擎、實時系統開發者參考。
一、控制流與分支優化
- 減少跳轉/分支:函數調用 = 兩次跳轉 + 棧操作。熱點路徑用
inline、展開循環。
- 優先迭代而非遞歸:避免棧溢出與調用開銷。
- 長 if-else 鏈 → switch:編譯器可生成跳轉表,單次跳轉。
- 熱分支前置:
if (likely) ... else ...(GCC __builtin_expect)。
二、內存訪問與數據佈局
- 多維數組按行優先訪問:
a[i][j] 與 a[i][j+1] 相鄰,a[i+1][j] 遠。倒序訪問導致 Cache Miss。
- 結構體熱點字段聚合:使熱點數據落在同一 Cache Line(通常 64B)。
- 避免過度使用局部變量:少量可進寄存器,大量則佔棧;考慮靜態/全局或池化。
- 減少函數參數:參數同樣走棧,超過 6 個(x64)會溢出到內存。
- 結構體傳引用不傳值:避免拷貝構造/析構開銷。
三、類型與運算優化
- 避免隱式類型轉換:整數↔浮點需跨寄存器文件,延遲 3~5 週期。
- 優先位運算替代乘除:
x * 8 → x << 3,x / 8 → x >> 3(無符號/正數)。
- 查找表慎用:L1 Cache 命中快,Miss 則比直接計算慢(三角函數除外)。
- 對象用復合賦值(+=/-=/*=/=):避免臨時對象構造/析構;基本類型用
+ 等更利於編譯器優化。
- 延後定義變量:僅在需要的作用域構造,省去構造/析構開銷。
- 前綴 ++obj 優於後綴 obj++:後綴需拷貝舊值。
四、模板與標準庫
- 謹慎用模板/STL:調試版極慢,發布版優化後尚可;熱點路徑手寫專用容器更可控。
- 避免計算期動態分配:
new/malloc 需鎖、系統調用、碎片。用對象池、棧分配、std::array、alloca。
五、Cache 與內存層級
- 了解 Cache Line 大小並對齊:
alignas(64) 熱點結構體。
- 大塊初始化用 memset/memcpy:編譯器會生成向量化指令(AVX/SSE)。
- 提前返回/跳出循環:射線三角形相交若
t < 0 直接返回,省去重心座標計算。
六、數學優化
- 手工化簡公式:編譯器不識別代數恆等式(如
sqrt(a) == sqrt(b) → a == b)。
- 除法倒數乘法:
x/y → x * (1/y),多次除法共用倒數。
- 循環不變量外提:
for (...) { const float inv = 1.0f/x; ... }。
- 遞推替代重算:
x[i+1] = x[i] + delta 代替每次從頭計算。
七、數值類型選擇
- 現代 CPU float/double 差異極小:64 位機上 double 常更快(寄存器寬度匹配),實測為準。
- 整數不再比浮點快:SSE/AVX 使浮點吞吐 ≥ 整數。
八、工程流程
- Profile 指導優化:
perf/VTune/Instruments 找真正熱點,別憑直覺。
- 編譯器優化旗標:
-O3 -march=native -flto -funroll-loops。
- 基準測試驗證:Google Benchmark / Catch2,防止「優化」變「劣化」。
- 優化時間 ≈ 2× 編碼時間:大師經驗,預留足夠調優窗口。
九、總結
優化是權衡藝術:可讀性 vs 性能、通用性 vs 專用化、開發速度 vs 運行速度。先測量,再優化,再驗證,方為正道。