这个问题在技术社区被问烂了,但每次刷到都能看到吵成一团。有人说“C++是C的超集,怎么可能比C快”,也有人搬出“模板元编程、编译期计算”来证明C++可以比C还猛。作为一个从嵌入式裸机写到底层服务端的C/C++开发者,我想认真把这件事掰开揉碎说清楚:C和C++哪个更快,本质上不是一个语言问题,而是一个工程问题。
先说结论,免得你往下翻得着急:在同一个开发者手里,用相同的优化思路、相同的编译器参数,去实现同一个功能,C和C++的最终性能差距通常不会超过几个百分点。真正拉开差距的,是“你用C++的哪些特性”以及“你为C放弃了什么抽象”。而且我见过不少情况,C++反而跑得比C快,原因是现代C++的编译期计算、模板内联和移动语义,让很多在C里只能靠宏和手写缓存的操作变得更加安全且高效。
这篇文章适合正在学C/C++的初学者、准备面试的学生,以及在工作里纠结选型的技术人。我会从语言差异、编译器优化、内存模型、实战编码、热词里涉及的具体问题(比如指针、随机数、字符串处理)一路展开,最后给出一份常见的性能误判排查清单。保证你看完能有一套自己的判断逻辑,而不是只会背“C快还是C++快”的答案。
1. 先搞清楚C和C++到底差在哪
1.1 从“纸面性能”到“实际性能”的距离
单纯比较语法层面,C和C++的底层运行机制几乎是一模一样的:函数调用、栈帧、寄存器操作、系统调用,最终都编译成机器码。C++也没有虚拟机,没有垃圾回收,没有运行时类型检查——所以它天然具备和C同级别的“裸性能”潜力。
但为什么总有人说C++慢?因为C++给程序员提供了太多“看起来很高级”的写法。
比如你写个std::vector<int>,用得顺手,很多新手不知道它扩容时会拷贝旧元素;你写个std::string做字符串拼接,连续+=可能反复触发堆分配。这些不是语言慢,是使用方式慢。反过来,如果你用C写一个动态数组,也得手动 realloc,手动 memcpy,你就能清楚看到每次分配有多大开销。C的优势在于“台上台下的动作你都看得见”,C++的优势在于“你看不见的动作可以用规则约束它”。
举个例子:C里实现多态靠函数指针表,每次调用都要多一次间接跳转;C++里实现多态靠虚函数表,也是一次间接跳转。它们在运行开销上几乎一致。但C++还能通过模板实现“编译期多态”,直接省掉这次间接跳转——这一点C反而做不到了。所以“C++一定更慢”这种说法,从机制层面就是站不住脚的。
1.2 隐式行为与抽象惩罚
C是一门“小而干净”的语言,它几乎不替你做任何事。数组下标你需要自己保证不越界,malloc 之后你需要自己记得 free,结构体复制就是按位拷贝,没有任何额外的“构造/析构”概念。
C++则引入了构造、析构、拷贝、移动、重载运算符等一堆隐式操作。这些操作本身都是可以内联、可以优化的,而且它们真正解决了很多C里靠约定俗成维持的隐患。如果你完全不用这些特性,把C++当C写,性能不会有差别;但你一旦开始用std::map、std::shared_ptr,就引入了额外的开销。
std::shared_ptr尤其典型:它要维护原子引用计数,每次拷贝和销毁都要执行原子操作。原子操作在多线程下是必要的,但如果你在单线程环境里手滑用了它,性能可能比裸指针慢一个数量级。这就是“抽象惩罚”——不是C++的抽象有问题,是选错了抽象。
我自己的经验是:性能敏感代码里,不是不能用C++特性,而是要清楚每个特性的成本。C++委员会在标准化过程中也一直强调“零开销原则”(zero-overhead principle):你不需要的功能,你不该为它买单;你使用的功能,其运行成本不应该比手工代码更高。这条原则保证了只要你用对特性,C++运行速度完全可以和C持平。
2. 性能差异的真正来源:编译器和优化水平
2.1 同一套后端,谁优化得更狠?
很多人忽略了一个事实:你在Linux上用gcc编译C程序和用g++编译C++程序,最终都是同一个编译器后端(最典型的是GCC和LLVM)。它们共享指令调度、寄存器分配、循环优化、向量化等优化流水线。单纯的语法差异,在后端优化面前往往会被抹平。
真正影响性能的是“前端语言能暴露多少优化机会”。C++因为拥有更丰富的类型信息,在后端做某些优化时反而可能比C更有利。比如通过模板生成的特化版本,因为类型已知,编译器可以做更精确的内联和常量传播;而C里如果依赖函数指针或宏,有些优化就做不到了。
我说一个真实测试过的例子:同样的快速排序,分别用C的qsort(传入函数指针)和C++的std::sort(传入模板比较器),在几百万个整数的排序上,std::sort通常会比qsort快 20% 到 50%。原因很简单:qsort在每次比较时都必须通过指针进行一次间接函数调用,而且比较参数要从void*转回具体类型,编译器很难内联;std::sort的比较器是模板实例化出的具体函数,可以直接内联进排序循环里,省掉了所有间接调用开销。
这就是“C++比C快”的最典型场景:更具体、更可见的代码信息帮助编译器生成了更好的机器码。如果你只盯着语法本身,完全看不到这一层。
2.2 优化选项与未定义行为的潜在隐患
性能对比如果不提编译参数,就是在耍流氓。最优化的C代码如果用-O0(无优化)编译,照样跑不过用-O2编译的C++代码。反过来也一样。所以任何“C更快”或“C++更快”的说法,都必须注明编译器和优化级别。
还有一个隐性问题:未定义行为。C和C++都包含大量未定义行为规则,比如有符号整数溢出、数组越界、空指针解引用。编译器会在优化时假设代码中不存在未定义行为,然后进行激进优化。如果代码触发了未定义行为,编译器可能生成“你完全没想到”的代码,最终导致性能暴涨或崩溃。
典型例子:有符号整数溢出在C和C++里都是未定义行为。你写for (int i = 0; i < n; i++),编译器可以根据循环不变量把整个循环优化成数学公式,前提是它认为n不会导致溢出。如果在C代码里无意中发生了溢出,可能整个程序逻辑都乱了。这不能怪语言,而是代码没有严格遵守契约。
我给初学者一个实在建议:不要为了“性能”去玩未定义行为,比如用int指针强转并解引用来省拷贝。除非你有十年经验,并且仔细阅读了编译器的汇编输出,否则这种优化往往得不偿失。
2.3 内联与链接优化
C++的类成员函数天然具备内联优势,因为函数定义通常和类定义放在同一个头文件里,编译器在翻译单元内就能看到函数体,可以直接内联。C中如果想把函数放头文件里,要么写成static inline,要么用宏。宏的问题是没有类型检查,维护起来很痛苦。
内联不只是省掉了函数调用开销,更重要的是它打开了更多优化的“窗户”。一个只有几行的小函数被内联后,调用点处的常量、变量状态都能传递进去,编译器可以进行死代码消除、常量折叠、公共子表达式复用。这往往是5%到15%的性能差距来源,累积起来非常可观。
2.4 链接时优化(LTO)与跨语言对比
还要提一下链接时优化(LTO)。现代编译器都支持将中间表示(GIMPLE或LLVM IR)保存到对象文件里,链接时再做一轮跨文件分析。这样即便函数定义在别的.c/.cpp文件里,也能做到内联和常量传播。
有LTO之后,C和C++的“头文件内联优势”差距被缩小了一些。但C++还有模板这个杀手锏:模板实例化天然在编译期展开,编译器能看到完整的模板实参,可以做很多自定义优化。这些是C完全没有的能力。
所以我在工程里经常说:如果你需要极致的性能,不要执着于用C还是C++,先检查你有没有开最高级优化、有没有开LTO、有没有针对性调整过热点路径。多数性能问题出在这里,而不是出在语言选型上。
3. 影响性能的实战因素:内存、指针、随机数与字符串
3.1 内存分配与缓存友好性
热词里出现了“c盘满了怎么清理”这种完全无关的词,但内存管理确实是C/C++性能对比中最核心的一环。我们可以借“内存”这个词展开:C和C++的性能差距,经常体现在“谁更擅长管理内存”。
C里创建动态数组需要malloc+free,每一次堆分配都有系统调用或内存池管理的成本。C++里如果用std::vector,它同样会使用分配器来向系统要内存,默认分配器底层也是new/delete,而new/delete又会调用malloc/free或者定制内存池。因此,在单纯的“分配/释放”开销上,两者没有本质区别。
区别出现在“你什么时候会分配内存”。
C语言里写字符串拼接,最常见的是这样:
char buf[256]; strcpy(buf, "hello "); strcat(buf, "world");如果字符串长度不确定,就不得不先strlen一遍,再malloc一块足够大的内存。这要求开发者精确计算长度,一旦漏算末尾的'\0',就会造成缓冲区溢出。
C++的std::string提供了一种更安全的封装,但如果你写:
std::string s = "hello "; s += "world"; s += "!";std::string会根据长度动态扩展容量,如果它每次追加都触发重分配,就会频繁malloc+memcpy。不过现代std::string实现通常有小字符串优化(SSO):长度较短的字符串直接存储在对象内部缓冲区里,不涉及堆分配。这就可能比C代码还要快——前提是字符串确实短。
很多性能敏感项目里,C程序员会提前算好最大长度,一次性分配,然后手工维护字符串结构;C++程序员可以类似地调用reserve()预分配容量。殊途同归:性能差距取决于你是否了解内存分配机制,而不是语言的“名字”。
缓存友好性也是一样。无论C还是C++,最终访问内存都是通过CPU缓存。如果你遍历一个struct数组,结构体越小、排列越紧凑,缓存命中率越高。C的struct不会自动调整内存布局,C++的class默认也是这样。不过C++可以通过[[no_unique_address]]、[[likely]]等属性(C++20/23)提供更精细的优化手段,C没有这些现代属性(至少标准层面没有统一)。这又是C++在激进调优时的一个武器。
3.2 指针用法与“指针就是性能”
热词里有“指针用法c++”。指针在C和C++中性能模型完全一样:它就是内存地址,解引用就是访问内存,没有魔法。但在实际使用中,C++的引用和智能指针会改变我们写代码的方式,进而影响性能。
C里频繁使用指针传递参数,是为了避免结构体拷贝。比如:
void process(struct Data *d) { // 直接操作d->xxx }C++里可以传引用:
void process(Data& d) { // 直接操作d.xxx }两者底层机器码很可能一模一样。但C++可以通过const修饰引用,让编译器明确这个函数不会修改对象,从而做一些更深入的优化。C里如果传const struct Data *也可以,但不少初学者会忘记加const,或者因为没有引用语法而干脆传值,造成无意义拷贝。
C++11之后移动语义解决了另一个C里非常难缠的问题:从函数返回一个“大对象”。C里要返回结构体,往往要通过输出参数:
void get_data(struct Data *out); // 调用方先分配,再传入指针C++可以直接返回对象:
Data get_data() { Data d; // ... return d; }如果编译器启用复制省略(copy elision,C++17中称为保底复制省略),返回值会直接在调用方的栈帧上构造,连一次移动拷贝都没有。这种写法不仅性能好,代码也更自然。可以说,在“返回大对象”这个具体场景,现代C++可以做到比同样逻辑的C更快,因为它的语义让编译器可以名正言顺地消除拷贝。
3.3 随机数生成:库实现带来的性能差异
热词里有“c++随机数”。C的rand()和C++的<random>库之间的性能差异经常被拿来说事。分开看:
rand()通常是简单的线性同余生成器(LCG),生成快,但质量低。- C++
std::mt19937是梅森旋转算法,生成质量高,但单个随机数生成成本也高。
但这不代表“C++随机数更慢”。C++标准库同样提供了轻量级的生成器,比如std::minstd_rand(也是LCG),速度可以和rand()持平。而且在现代硬件上,rand()的瓶颈往往不是算法,而是它内部使用了进程级的隐藏状态,可能导致线程安全问题和缓存冲突。
如果你要做高性能蒙特卡洛模拟,最优的选择往往不是rand()也不是mt19937,而是自己实现一个基于xorshift或splitmix64的快速生成器,或者用C++11的pcg库。这跟语言无关,而是工程选型问题。
3.4 字符串与数组:初始化、转换、逆序
热词里还有“c++字符串数组初始化”“c++字符串转数组”“字符串逆序输出c”。这些操作是日常编码的热点,也常常成为性能对比的素材。
在C里,字符串数组初始化很简单:
char s[] = "hello";如果要做逆序,往往原地交换字符,代码直观且高效。在C++里,如果自定义一个std::string并原地逆序,也可以直接用下标访问,毫不逊色。但 C++ 标准库还提供了std::reverse这种算法,它专门针对随机访问迭代器做了优化,编译器可以把循环向量化。手写循环的时候,你可能不会想到要告诉编译器“这里可以矢量化”,但标准库算法通常在编写时就考虑了这些。
所以“字符串逆序”这种本来没多大性能差别的操作,C++反而能更轻松地压榨出向量化的收益。如果你用C写,需要自己处理循环展开、指针别名限制(restrict)等问题,才能达到同样的效果。这不是说C做不到,而是“同样能力”的实现成本不一样。
字符串转数组也一样。C里可以用sscanf或者手工遍历;C++里可以用std::from_chars(C++17),它专门针对数值解析做了优化,通常比sscanf快几倍,而且天然支持无异常模式。这种“标准库水准”的差异,会让同样的业务逻辑在C++里更容易写出高性能版本。
4. 现代C++与C的性能博弈:哪些特性是加速器,哪些是坑
4.1 constexpr、static、final/override 怎样影响性能
热词里有“c++ final、static、const等详解”。这几个关键字看似无关,实际都会对性能产生直接或间接影响。
const告诉编译器这个值不会变,编译器可以在编译期进行常量替换、死代码消除,甚至把整个计算提前到编译期。在C里也有const,但 C++ 的constexpr更进一步,允许在编译期求值函数,相当于把运行成本完全移除。static在C中用于限制符号作用域,在C++中还涉及静态成员变量和局部静态变量。局部静态变量在多线程环境下的初始化有一定开销(C++11之后是线程安全的),但之后访问就是一次平凡分支。如果该对象非常重,且不需要线程安全,也可以改用其他方案。final在C++中标注一个类不可被继承,或一个虚函数不可再被覆盖。它可以帮助编译器去虚拟化(devirtualization):如果编译器知道一个虚函数调用最终只可能落到唯一实现上,它就能把虚调用转换成立即调用,甚至内联。这在高频调用场景能带来明显的性能提升。
这些特性C都没有,但C根本不需要,因为C没有继承和多态。所以C++的性能优势其实来自于“它能用语言特性明确告诉编译器更多事实”。做性能对比时,如果你比的是C的写法与C++的写法在同一优化级别下的结果,C++的这些特性就是合法且合理的加速手段。
4.2 模板:为什么C++可以做到比C更“定制”
模板是C++最强大也最容易被滥用的特性。从性能角度看,模板让“类型”参与编译期计算,从而生成特化代码。比如冒泡排序算法(热词里有“冒泡排序算法c++”),用模板写:
template<typename T> void bubble_sort(T* arr, size_t len) { for (size_t i = 0; i < len - 1; ++i) { for (size_t j = 0; j < len - i - 1; ++j) { if (arr[j] > arr[j + 1]) { T tmp = arr[j]; arr[j] = arr[j + 1]; arr[j+1] = tmp; } } } }当传入int*,编译器实例化一份针对int的版本,所有比较和拷贝都是纯CPU操作。如果传说C代码,为了支持多种类型,要么用宏,要么用void*加函数指针,后者必然损失性能。
更极致的是模板元编程。很多库可以在编译期完成展开循环、生成查找表、计算斐波那契数列等任务,运行时真正执行的机器码被精简到了最小。C完全没有这种能力,所以某些场景下“C++编译出来的程序比C更优”是事实。
当然,模板也会导致代码膨胀、编译时间变长。性能上如果模板实例化过多,指令缓存压力反而变大。这就是为什么我说“滥用特性会翻车”,但“用对特性可以超车”。
4.3 异常机制与RTTI的性能代价
说到C++的坑,最典型的就是异常和运行时类型信息(RTTI)。
C++异常的设计目标是“零开销正常路径”。也就是说,只要没有异常抛出,异常处理代码不应该比无异常版本慢。现代编译器通过“零成本异常模型”(基于表驱动的展开机制)基本实现了这个承诺:正常控制流上不会插入额外分支,错误路径才查表跳转。然而这带来的副作用是二进制体积变大、分支预测对错误路径不友好,但严格来说正常路径性能确实几乎没有损耗。
RTTI(typeid、dynamic_cast)则不一样,它每次dynamic_cast都要查运行时类型信息表,成本较高。C里没有RTTI,很多C语言项目会咬紧牙关只用手写的类型标签。如果性能敏感且必须多态,C++也未必非要跑得比C慢——你完全可以用有限类层次+自定义类型枚举来替代RTTI,代价是失去部分动态安全性。这是“工程取舍”,不是“语言优劣”。
4.4 虚拟存储器管理:C和C++在操作系统层面的共同底层
热词里还有“虚拟存储器管理c语言”。这听起来很底层,但恰恰说明很多人关心内存和性能关系。虚拟内存管理是操作系统提供的机制,C和C++程序在运行时会共同使用它。无论你用malloc还是new,最终都需要调用操作系统的内存映射接口来获取虚拟内存页。语言本身不提供“另一个更快的内存模型”。
因此,在讨论“C和C++谁更快”时,不要指望换一个语言就能绕过虚拟内存开销。你唯一能做的,是减少小内存块的频繁分配、提高内存访问局部性、避免缺页错误。这些优化手段在C和C++里都可以实现,C++的RAII和容器反而更容易管理资源生命周期,减少内存泄漏和碎片。
5. 如何在真实项目中评判与提升性能
5.1 写基准测试要避开的五个坑
判断C和C++谁更快,不能靠感觉,必须靠基准测试。但基准测试本身也容易骗人。我整理几个常见的坑:
- 优化器太聪明,把空循环删了。一个什么都不做的函数被
-O2优化后可能直接返回0,测试结果毫无意义。必须把一个“无法被消除”的变量累加进结果。 - 没有预热阶段。CPU频率、分支预测器、缓存状态都会影响测试结果。先跑几轮,稳定后再采样。
- 测试数据和真实数据差别太大。如果基准测试全是顺序访问,可能命中缓存,导致结果虚高。真实场景可能随机访问、可能多线程竞争。
- 随手开了
-O0比性能。除了调试,没人会用-O0部署。默认请-O2/-O3比较。 - 没有考虑指令集差异。如果你的机器支持AVX2,而编译器没有开启
-march=native,那再快的代码也只是在用保守的指令集。这跟语言无关,但会直接影响对比结果。
正确的做法是:把C和C++的版本放在同一个编译系统里,用同一套优化参数,跑同一个测试框架(比如Google Benchmark),并且记录CPU频率、编译器版本、硬件型号。这样得出的数据才有参考价值。
5.2 环境配置:从VSCode开始避免性能优化“被关掉”
热词里有“vscode配置c/c++环境”,我顺便聊聊这个。很多人用VSCode写C/C++,默认的tasks.json里可能不带优化参数。你在编辑器里点击“运行”时,用的可能是-O0,然后惊讶地发现自己的程序跟别人的相差好几倍。这不是语言的问题,是你根本没有打开编译器的优化开关。
我建议在tasks.json的编译参数里明确加上:
"-O2"如果你要做性能测试,甚至可以加上:
"-O3", "-march=native"-march=native会让编译器针对你的CPU生成专用的指令集,性能可以明显提升,但换到别的机器上可能无法运行,所以生产环境要谨慎使用。在VSCode里写完C/C++代码,第一时间确认编译命令里是不是带了优化选项,这能避免你做出完全错误的性能判断。
5.3 扩展思路:用C++写小游戏与学习指针
热词里有很多“c++小游戏”“c++ 游戏”“c++入门”。作为性能探索的入门项目,写一个小游戏是很好的方式。游戏循环通常需要严格控制在16毫秒帧预算内,这会逼迫你关注每帧的内存分配、对象生命周期和算法复杂度。
在C++里写游戏,你可能会惯用std::vector保存实体列表,用智能指针管理资源。然后你会发现,如果每帧都在创建大量临时对象和智能指针,帧率就会骤降。这时候你再尝试把它改成对象池、优化存储结构,性能立刻回来。
这个过程能让你真实感受到:C和C++的性能上限几乎一样,瓶颈往往在写代码的人没有理解底层机制。VSCode里的代码补全不会告诉你push_back会拷贝,但调试器和性能分析器会。
5.4 与“C盘清理”有关的插曲:环境问题对性能判断的干扰
热词里有“c盘清理”“c盘满了怎么清理”等,看起来和主题无关,但我在帮朋友排查编译性能问题时,真的遇到过因为C盘空间不足导致编译器无法生成临时文件、从而编译速度奇慢甚至失败的例子。如果你在Windows上用VSCode开发C/C++,磁盘空间紧张时,编译器的缓存和预编译头文件都可能被清理工具误伤,导致每次编译都从零开始。
这种“环境问题”和“语言性能”无关,但很容易让人误以为C++编译慢、运行慢。我这里提醒一句:做性能对比前,先保证磁盘空间充足、编译器版本一致、优化参数一致,否则你分析出来的都是噪声。另外,Visual C++ Redistributable(热词里有“microsoft visual c++ redistributable”)是Windows下运行C++程序必需的运行库,如果缺失,程序直接启动失败,这同样不是C++本身慢,而是安装配置问题。
6. 常见问题与排查技巧实录
6.1 为什么我测出来C比C++快很多?
先看你的编译参数。如果你用GCC编译C文件开-O2,但用G++编译C++文件时忘记加优化参数,或者默认用了-O0,差距当然大。把参数统一后再测。
然后看你的测试代码:是不是C里用了静态数组、C++里用了std::vector且反复push_back没有reserve?这种对比不公平。C代码如果用一个固定数组,C++代码也应该在初始化时就reserve好容量,或者用std::array。
最后看是否涉及异常和RTTI。如果你的C++代码抛了异常,或者使用了dynamic_cast,性能下降是正常的。这些特性不是免费午餐,但你可以避免使用它们。
6.2 为什么我测出来C++比C快?
这不奇怪,常见原因在前面说过:C++的模板内联、移动语义、标准库算法优化。另外C++更容易写出“编译器能理解意图”的代码,比如:
std::vector<int> v(n); std::iota(v.begin(), v.end(), 0); long long sum = std::accumulate(v.begin(), v.end(), 0LL);这串代码可以用SIMD向量化,而手写C循环如果不加#pragma omp simd或无法证明无别名,可能被保守处理,导致更慢。尤其是在-O3下,std::accumulate和手写循环的差距很容易普遍存在。
6.3 用C++是不是必须用“现代特性”才能快?
不一定。如果团队都是C程序员出身,用C++但你坚持写“带类的C”风格,性能也完全够用。C++的优势是“渐进式引入”,你可以在关键路径上用std::sort替代手写排序,用std::vector替代裸数组,用移动语义替代深拷贝。其余地方保持C风格也无妨。
不过要注意:“带类的C”可能比C更容易变慢。因为你会默认调用一些小函数,觉得它们是“内联的”,但如果没有inline且定义在.cpp里,编译器可能没法内联,反而造成不必要的开销。所以无论你用什么风格,都要对编译器可见性有清晰认知。
6.4 性能分析工具怎么用?
不要凭感觉。Linux下用perf,Windows下用Visual Studio的性能探查器,macOS下用Instruments。先用性能分析器定位热点函数,再看汇编确认优化是否生效。
很多时候你会发现,性能瓶颈完全不在“语言对比”的层面上,而在I/O、锁竞争、缓存未命中、系统调用频率。语言只是决定了你写这些逻辑的语法成本,真正的性能大头操作系统和硬件说了算。
6.5 有没有“必赢”的选择?
如果你对性能有极致要求、团队经验丰富且愿意手写底层优化,选C也很合理。如果你希望代码可维护性高、抽象能力强,同时仍然要求高性能,选现代C++更合适。大多数服务端中间件、游戏引擎、数据库底层都是用C++写的;而操作系统内核、嵌入式驱动、某些通信协议栈更偏爱C。这从来不是一场“非黑即白”的比赛。
我的个人体会是:与其纠结“C和C++哪个更快”,不如多熟悉你用的编译器、性能分析器、缓存结构、系统调用模型。这些知识在C和C++里都是通用的。你把这套底层能力练扎实了,用任何一门语言都能写出高性能程序;如果你只是抱着“语言决定性能”的标签,那不论选C还是C++,你都很难挖掘出真正的潜力。
最后再分享一个小技巧:做性能对比时,把两个实现都编译成汇编,用objdump或godbolt.org对比关键循环。你会直观看到编译器到底把C和C++代码变成了什么样的机器指令。很多时候,看到汇编的那一刻,你心里就已经有了答案——它们底层真的是同一种东西。区别只在于,你能给编译器提供多少“优化线索”。