C語言中奇技淫巧04-僅對指定函數啟用編譯優化

相信很多人使用GCC編譯代碼時,都會接觸到gcc -O0/1/2/3/s,知道它可以對工程進行全局優化。

事實上,除了全局優化外,使用GCC擴展方式,我們還可以僅對部分關鍵函數實施差異化編譯優化。

在GCC編譯器中,attribute((optimize(“Ox”))) 可以為單個函數顯式指定優化級別,覆蓋全局編譯選項(如 -O0 或 -Os)。這一特性適用于需要對特定函數進行針對性優化的場景(例如性能關鍵路徑),而其他函數保持較低優化級別以便調試。
使用示例:

#include <stdio.h>// 全局編譯級別為 -O0(默認不優化)
// 但對 foo 函數單獨啟用 O3 優化
__attribute__((optimize("O3")))
int foo(int a, int b) {int i, j, v;for (i = 0; i < a; i++) {for (j = 0; j < b; j++) {v += i*j;	}}return v;
}//本函數使用默認優化級-O0,與foo()進行優化對比
int foo2(int a, int b) {int i, j, v;for (i = 0; i < a; i++) {for (j = 0; j < b; j++) {v += i*j;	}}return v;
}int main(void) {int a = 0, b = 0;a = foo(10, 2); // main 函數仍遵循全局 -O0b = foo(10, 2);return 0;
}

使用gcc test.c -g 進行編譯,并使用objdump -dS a.out進行反匯編,可以看出foo()foo2()函數匯編代碼大不相同。

其中,foo()由于函數包含 計算密集型嵌套循環(v += i*j),-O3 觸發了 自動向量化,通過 128位 SSE2 指令(如 pmuludq、paddd)并行處理多個 j 值的乘法和累加,將循環吞吐量提升數倍。

__attribute__((optimize("O3")))
int foo(int a, int b) {1130:       f3 0f 1e fa             endbr64int i, j, v;for (i = 0; i < a; i++) {1134:       85 ff                   test   %edi,%edi1136:       0f 8e f3 00 00 00       jle    122f <foo+0xff>113c:       41 89 f1                mov    %esi,%r9d113f:       41 89 f2                mov    %esi,%r10d1142:       44 8d 5e ff             lea    -0x1(%rsi),%r11d1146:       31 c9                   xor    %ecx,%ecx1148:       41 c1 e9 02             shr    $0x2,%r9d114c:       41 83 e2 fc             and    $0xfffffffc,%r10d1150:       45 31 c0                xor    %r8d,%r8dfor (j = 0; j < b; j++) {1153:       85 f6                   test   %esi,%esi1155:       0f 8e c1 00 00 00       jle    121c <foo+0xec>115b:       66 0f 6f 35 bd 0e 00    movdqa 0xebd(%rip),%xmm6        # 2020 <_IO_stdin_used+0x20>1162:       001163:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)1168:       41 83 fb 15             cmp    $0x15,%r11d116c:       0f 86 b9 00 00 00       jbe    122b <foo+0xfb>1172:       66 41 0f 6e f8          movd   %r8d,%xmm7
int foo(int a, int b) {1177:       66 0f 6f 1d 91 0e 00    movdqa 0xe91(%rip),%xmm3        # 2010 <_IO_stdin_used+0x10>117e:       00117f:       31 c0                   xor    %eax,%eax1181:       66 0f ef d2             pxor   %xmm2,%xmm21185:       66 0f 70 e7 00          pshufd $0x0,%xmm7,%xmm4118a:       66 0f 6f ec             movdqa %xmm4,%xmm5118e:       66 0f 73 d5 20          psrlq  $0x20,%xmm51193:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)1198:       66 0f 6f c3             movdqa %xmm3,%xmm0119c:       83 c0 01                add    $0x1,%eax119f:       66 0f fe de             paddd  %xmm6,%xmm3v += i*j;11a3:       66 0f 6f c8             movdqa %xmm0,%xmm111a7:       66 0f 73 d0 20          psrlq  $0x20,%xmm011ac:       66 0f f4 cc             pmuludq %xmm4,%xmm111b0:       66 0f f4 c5             pmuludq %xmm5,%xmm011b4:       66 0f 70 c9 08          pshufd $0x8,%xmm1,%xmm111b9:       66 0f 70 c0 08          pshufd $0x8,%xmm0,%xmm011be:       66 0f 62 c8             punpckldq %xmm0,%xmm111c2:       66 0f fe d1             paddd  %xmm1,%xmm2for (j = 0; j < b; j++) {11c6:       44 39 c8                cmp    %r9d,%eax11c9:       75 cd                   jne    1198 <foo+0x68>11cb:       66 0f 6f c2             movdqa %xmm2,%xmm011cf:       66 0f 73 d8 08          psrldq $0x8,%xmm011d4:       66 0f fe d0             paddd  %xmm0,%xmm211d8:       66 0f 6f c2             movdqa %xmm2,%xmm011dc:       66 0f 73 d8 04          psrldq $0x4,%xmm011e1:       66 0f fe d0             paddd  %xmm0,%xmm211e5:       66 0f 7e d0             movd   %xmm2,%eax11e9:       01 c1                   add    %eax,%ecx11eb:       44 89 d0                mov    %r10d,%eax11ee:       44 39 d6                cmp    %r10d,%esi11f1:       74 19                   je     120c <foo+0xdc>11f3:       89 c2                   mov    %eax,%edx11f5:       41 0f af d0             imul   %r8d,%edx11f9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)1200:       83 c0 01                add    $0x1,%eaxv += i*j;1203:       01 d1                   add    %edx,%ecxfor (j = 0; j < b; j++) {1205:       44 01 c2                add    %r8d,%edx1208:       39 f0                   cmp    %esi,%eax120a:       7c f4                   jl     1200 <foo+0xd0>for (i = 0; i < a; i++) {120c:       41 83 c0 01             add    $0x1,%r8d1210:       44 39 c7                cmp    %r8d,%edi1213:       0f 85 4f ff ff ff       jne    1168 <foo+0x38>}}return v;
}1219:       89 c8                   mov    %ecx,%eax121b:       c3                      retfor (i = 0; i < a; i++) {121c:       41 83 c0 01             add    $0x1,%r8d1220:       44 39 c7                cmp    %r8d,%edi1223:       0f 85 2a ff ff ff       jne    1153 <foo+0x23>1229:       eb ee                   jmp    1219 <foo+0xe9>for (j = 0; j < b; j++) {122b:       31 c0                   xor    %eax,%eax122d:       eb c4                   jmp    11f3 <foo+0xc3>for (i = 0; i < a; i++) {122f:       31 c9                   xor    %ecx,%ecx
}1231:       89 c8                   mov    %ecx,%eax1233:       c3                      ret

通過 SIMD 指令并行處理數據、循環分塊適配向量長度、寄存器深度復用以消除內存訪問,最終實現執行速度的大幅提升。

而使用默認優化級別的foo2()函數未對循環做任何展開,也未調用SIMD指令進行優化:

//本函數使用默認優化級-O0,與foo()進行優化對比
int foo2(int a, int b) {1234:       f3 0f 1e fa             endbr641238:       55                      push   %rbp1239:       48 89 e5                mov    %rsp,%rbp123c:       89 7d ec                mov    %edi,-0x14(%rbp)123f:       89 75 e8                mov    %esi,-0x18(%rbp)int i, j, v;for (i = 0; i < a; i++) {1242:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%rbp)1249:       eb 23                   jmp    126e <foo2+0x3a>for (j = 0; j < b; j++) {124b:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)1252:       eb 0e                   jmp    1262 <foo2+0x2e>v += i*j;1254:       8b 45 f4                mov    -0xc(%rbp),%eax1257:       0f af 45 f8             imul   -0x8(%rbp),%eax125b:       01 45 fc                add    %eax,-0x4(%rbp)for (j = 0; j < b; j++) {125e:       83 45 f8 01             addl   $0x1,-0x8(%rbp)1262:       8b 45 f8                mov    -0x8(%rbp),%eax1265:       3b 45 e8                cmp    -0x18(%rbp),%eax1268:       7c ea                   jl     1254 <foo2+0x20>for (i = 0; i < a; i++) {126a:       83 45 f4 01             addl   $0x1,-0xc(%rbp)126e:       8b 45 f4                mov    -0xc(%rbp),%eax1271:       3b 45 ec                cmp    -0x14(%rbp),%eax1274:       7c d5                   jl     124b <foo2+0x17>}}return v;1276:       8b 45 fc                mov    -0x4(%rbp),%eax
}1279:       5d                      pop    %rbp127a:       c3                      ret

如果需要對多個函數應用相同優化,也可使用 #pragma GCC optimize 作用于代碼塊:

#pragma GCC push_options
#pragma GCC optimize("O2")int bar(int x) { /* O2 優化 */ }
int baz(int y) { /* O2 優化 */ }#pragma GCC pop_options // 恢復全局優化級別

注意事項:

  1. 不是 C 語言標準!!!C 語言標準(如 C99、C11、C17 等)僅定義了語言的語法、語義和標準庫,未規定編譯器優化相關的屬性語法。attribute 關鍵字是 GCC(GNU Compiler Collection)為代表的編譯器引入的 非標準擴展,用于向編譯器傳遞額外信息(如優化策略、代碼生成約束等)。
    主要由 GCC、Clang 等兼容 GCC 擴展的編譯器支持,MSVC、ICC 等其他編譯器可能不支持或使用不同語法(如 MSVC 使用 __declspec 或 #pragma)。若代碼中使用此類擴展,可能導致在非 GCC 系編譯器上編譯失敗,需通過條件編譯(如 #ifdef GNUC)處理兼容性。
  2. 優化級別語法: 可指定具體級別(O0/O1/O2/O3/Os),或附加選項(如 optimize(“O2”, “unroll-loops”))。
  3. 與全局優化的關系: 函數屬性優先級高于全局編譯選項,但部分全局優化(如 -ffast-math)可能仍會影響函數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916357.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916357.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916357.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HTML Style 對象深度解析:從基礎到高級應用

一、Style 對象的核心概念定義與作用 Style 對象是 HTML DOM 中用于操作元素內聯樣式的接口&#xff0c;通過 element.style 訪問。它允許動態修改元素的 CSS 屬性&#xff0c;但僅能直接影響內聯樣式&#xff08;即通過 style 屬性直接寫在標簽中的樣式&#xff09;。與外部樣…

【C++】定義常量

在 C 中&#xff0c;有兩種簡單的定義常量的方式&#xff1a; 使用 #define 預處理器。使用 const 關鍵字。 #define 預處理器 #include <iostream> using namespace std;#define LENGTH 10 #define WIDTH 5 #define NEWLINE \nint main() {int area; area LENGTH …

基于遺傳算法的多無人車協同偵察與安全保護策略優化

基于遺傳算法的多無人車協同偵察與安全保護策略優化 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家&#xff0c;覺得好請收藏。點擊跳轉到網站。 1. 引言 1.1 研究背景與意義 隨著無人系統技術的快速發…

python面向對象編程詳解

面向對象編程&#xff08;OOP&#xff09;是一種以對象為核心的編程范式。Python全面支持OOP&#xff0c;主要包含以下核心概念&#xff1a;一、類與對象1.類(Class)類是創建對象的模板或藍圖&#xff0c;它定義了對象的屬性和方法。class Dog:# 類屬性&#xff08;所有實例共享…

快速入門Socket編程——封裝一套便捷的Socket編程——導論

快速入門Socket編程——封裝一套便捷的Socket編程——導論 前言 ? 這里是筆者打算做的Socket編程的第二部分&#xff0c;也就是核心的討論我們Socket編程本身。 導論 ? 我們知道&#xff0c;一個經典的服務器套接字的處理流程是如下的&#xff1a; 創建一個指定傳輸層和網絡層…

【Mermaid 離線工具】Mermaid 流程圖生成器 - 高清PNG輸出,一鍵生成專業級流程圖!

文章目錄 Mermaid 流程圖生成器(離線版本):高效繪圖,離線也能玩轉專業可視化 一、Mermaid:文本繪圖的 “魔法語法” 二、離線版生成器:功能與優勢解析 (一)離線可用,場景更靈活 (二)操作流程:簡單五步,產出專業圖表 (三)界面設計:簡潔直觀,降低使用門檻 三、應…

haproxy原理及實戰部署

一、負載均衡 負載均衡是網絡架構和分布式系統中至關重要的技術&#xff0c;其核心作用是將大量的并發請求或數據流量合理分配到多個服務器&#xff08;或其他資源節點&#xff09;上&#xff0c;從而解決單節點壓力過大、資源利用率低、系統穩定性差等問題。 作用1. 提高系統吞…

jwt 在net9.0中做身份認證

一、新建net9.0項目WebApplication1&#xff0c;安裝包 <ItemGroup><PackageReference Include"Microsoft.AspNetCore.Authentication.JwtBearer" Version"9.0.7" /><PackageReference Include"Swashbuckle.AspNetCore" Version&…

【機器學習深度學習】微調能改變模型“智商”嗎?——模型能力與知識的本質解析

目錄 前言 一、模型的“知識”與“能力”&#xff1a;兩種不同的智能 第一種&#xff1a;淺層知識&#xff08;記憶 模式識別&#xff09; 第二種&#xff1a;深層能力&#xff08;推理 理解&#xff09; 二、微調&#xff1a;改變的是“經歷”&#xff0c;不是“天賦”…

oracle數據庫表空間碎片整理

oracle數據庫表空間碎片整理 表空間碎片情況檢查 表空間碎片問題處理 收縮表 表空間手動整理 exp/imp導出再導入 移動表到新的表空間 表空間碎片情況檢查 對比表實際使用空間和數據文件占用空間: --實際數據占用空間 select tablespace_name,round(sum(bytes/1024/1024/1024…

為什么需要可重入鎖

在黑馬點評項目實戰中&#xff0c;提到了可重入鎖&#xff0c;然后我想到了是不是不同業務在同一線程內反復獲取同一把鎖。本文來討論一下為什么鎖需要可重入。一、可重入鎖的核心&#xff1a;“同一線程多次獲取同一把鎖”??可重入&#xff08;Reentrant&#xff09;?? 的…

【AI】聯網模式

【AI】聯網模式 文章目錄【AI】聯網模式1. 簡介2. 接入步驟2.1 引入依賴2.2 方法構建2.3 接口構建1. 簡介 在使用聯網模式之前&#xff0c;我們如果問起ai一些最近網絡上流傳的一些東西&#xff0c;它可能并不能準確的給你描述出來&#xff0c;因為它的知識庫更新時間可能停留…

第10篇:實戰驗收篇

&#x1f50d; 實戰演練&#xff1a;多條件房源查詢 需求描述 查找一套符合以下條件的房子&#xff1a; 預算&#xff1a;2000–3000元區域&#xff1a;天河區戶型&#xff1a;兩房 關鍵詞&#xff1a;多條件查詢 AND BETWEEN LIKE 組合運用&#x1f3ac; 開場白“聽起來不難&a…

深入解析YARN中的FairScheduler與CapacityScheduler:資源分配策略的核心區別

YARN資源調度器概述在Hadoop生態系統中&#xff0c;YARN&#xff08;Yet Another Resource Negotiator&#xff09;作為核心資源管理平臺&#xff0c;其架構設計將計算資源管理與作業調度解耦&#xff0c;形成了"全局資源管理器&#xff08;ResourceManager&#xff09;節…

基于Seata的微服務分布式事務實戰經驗分享

基于Seata的微服務分布式事務實戰經驗分享 1. 業務場景描述 在電商系統中&#xff0c;用戶下單會涉及多個微服務&#xff1a;訂單服務&#xff08;Order Service&#xff09;、庫存服務&#xff08;Inventory Service&#xff09;、賬戶服務&#xff08;Account Service&#x…

Linux庫——庫的制作和原理(2)_庫的原理

文章目錄庫的原理理解目標文件ELF文件讀取ELF的工具——readelfELF從形成到加載的輪廓ELF形成可執行文件ELF可執行的加載理解鏈接與加載靜態鏈接ELF加載和進程地址空間虛擬地址 & 邏輯地址重新理解進程地址空間動態鏈接和動態庫的加載進程如何找到動態庫多個進程之間如何共…

Redis C++客戶端——通用命令

目錄 代碼案例 get和set部分 exists部分 del部分 keys部分 expire部分 type部分 本篇文章主要是通過redis-plus-plus庫使用通用命令。 代碼案例 下面用一個代碼演示&#xff1a; #include <sw/redis/redis.h> #include <iostream> #include <vecto…

手機開啟16k Page Size

我買了一個pixel8的手機&#xff0c;系統是Android16,如下操作都是基于這個手機做的。 https://source.android.com/docs/core/architecture/16kb-page-size/16kb-developer-option?hlzh-cn#use_16kb_toggle 使用 16 KB 切換開關 按照開發者選項文檔中的指示啟用開發者選項。…

VLAN的劃分(基于華為eNSP)

VLAN的劃分 前言&#xff1a;為什么VLAN是現代網絡的“隱形骨架”&#xff1f; 當一臺辦公室電腦發送文件給隔壁工位的同事時&#xff0c;數據如何精準抵達目標而不“打擾”其他設備&#xff1f;當企業財務部的敏感數據在網絡中傳輸時&#xff0c;如何避免被其他部門的設備“窺…

從壓縮到加水印,如何實現一站式圖片處理

當你需要對大量圖片進行相同或相似的操作時&#xff08;例如壓縮、裁剪、調整尺寸、添加水印等&#xff09;&#xff0c;逐個處理會非常耗時。批量處理工具可以一次性處理數百張圖片&#xff0c;大大節省了時間。這是一款極致輕巧的圖片處理利器&#xff0c;體積僅有652KB&…