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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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&…