当前位置: 首页 > news >正文

说嵌入式不能用C++的,你们写过超过10万行的嵌入式项目吗?

说嵌入式不能用C++的,你们写过超过10万行的嵌入式项目吗?

一句话观点:在MCU上跑C++确实是"杀鸡用牛刀",但在超过5万行代码的嵌入式Linux应用中,不用C++才是给自己找麻烦。

先交代背景,免得被喷。

我从2008年开始做嵌入式,前7年纯C,后11年C和C++混用。做过裸机、RTOS、嵌入式Linux。用C++写过最复杂的项目是一个带图形界面的医疗诊断设备,纯C++代码12万行+驱动层C代码3万行,跑在ARM Cortex-A7上。

所以别跟我说"你没在嵌入式里写过C++"——我写了十几年了。

也别跟我说"C++不适合嵌入式"——我拿C++做的产品已经卖了上万台,通过了医疗认证,至今没出过因为C++特性导致的严重bug。

我想说:关于C++在嵌入式领域的争论,大部分观点都是建立在"没写过大型嵌入式项目"这个前提下的。


反对C++进嵌入式的三个"经典论据",一个一个拆

论据一:“C++太臃肿,不适合资源受限的环境”

这话在1985年成立,在2026年已经不成立很久了。

我们来算笔账:

一个典型的ARM Cortex-M4单片机,比如STM32F4,有192KB RAM、1MB Flash。你告诉我C++的哪个特性是这192KB跑不动的?

  • 虚函数?一个vtable指针4字节,一个虚函数表就几KB。
  • 模板?编译后生成的是具体代码,不会比手写的C代码更大(实际上因为编译器的优化,模板生成的代码往往比手写C更紧凑)。
  • 异常?谁在嵌入式里开异常?关掉就行了。-fno-exceptions是标准配置。
  • RTTI?同上,-fno-rtti

真正导致C++"臃肿"名声的,是一些程序员滥用特性(比如在中断里new/malloc、深度继承链、滥用模板元编程),这是人的问题,不是语言的问题。

我最近的一个项目,C++编译出来的固件大小是208KB,而之前用C写的同功能固件是196KB。差距12KB,不到6%。而开发时间缩短了大约30%,因为C++的vector、string、智能指针、RAII机制帮我省了大量手写内存管理的时间。

你告诉我,这6%的Flash代价值不值?

论据二:“C++的抽象会掩盖底层细节,不适合做嵌入式”

这个论据我听了十几年,每次听都觉得好笑。

嵌入式工程师最引以为傲的能力之一就是"对底层了如指掌"。于是很多人形成了路径依赖:“我理解的才是好的,我不理解的封装都是坏的。”

但问题来了——你对底层的"了如指掌"到底给你带来了多少实际收益?

你用C写了一个UART驱动,对每个寄存器的每一位都了如指掌。但你的队友接手后,看了三天才看懂你的代码。因为你的"了如指掌"只在你的脑子里,代码里全是位运算和宏定义魔法。

换成C++:

classUART{// 底层寄存器都在这里,能看懂吗?uint32_tvolatile*DR=reinterpret_cast<uint32_t*>(0x40011000);public:// 但是上层使用者不需要管这些voidsend(conststd::vector<uint8_t>&data){for(autobyte:data){*DR=byte;while(!(*DR&0x80));// 等待发送完成}}};

底层细节还在那里,完全没丢。只是通过类封装给了调用者一个干净的接口。这叫"抽象",不叫"掩盖"。

你总不能说TSMC在制造芯片的时候,因为不知道你写的每个晶体管是干嘛的,所以芯片就不好用吧?

论据三:“嵌入式团队没几个人会C++,上了C++谁来维护?”

这个论据是最诚实的,也是最有道理的。

如果你们团队5个人,4个只会C,1个C/C++混用,那确实不应该用C++。这不是C++的问题,是团队技能的问题。

但我想反问一句:既然你知道C++有好处,为什么不去学?

2002年的时候,大部分嵌入式工程师还只会汇编。那时候有人说"用C做嵌入式",也被骂"C太高级了,掩盖了底层细节"。

你看,历史总是惊人的相似。每个时代的技术保守派都说着同样的话,只是关键词换了一下。


C++在嵌入式里到底适合干什么?

说了这么多,我也不是主张"所有嵌入式项目都应该用C++"。要分场景。

适合用C++的场景:

  • ✅ 代码量超过5万行的嵌入式Linux应用
  • ✅ 有复杂状态机/业务逻辑的可穿戴设备固件
  • ✅ 需要图形界面(LVGL/CSTML/emWin)的设备
  • ✅ 网络协议栈/物联网平台
  • ✅ 需要长期维护的产品(C++的强类型和封装让重构更安全)
  • ✅ 团队有2个以上C++熟练成员

不适合用C++的场景:

  • ❌ 裸机/RTOS上的简单外围控制(点灯、读传感器)
  • ❌ ROM/RAM以KB为单位的超低端MCU(4KB以内的)
  • ❌ 团队全员零C++经验
  • ❌ 硬实时中断处理代码(这部分本来也应该用C或汇编)

我个人的经验法则:

小于1万行

1-5万行

5-20万行

大于20万行

Flash < 64KB

Flash > 256KB

会C++

不会C++

项目规模

C语言

C语言优先

C++优先, C配合

必须C++, 否则维护成本爆炸

MCU资源

汇编/C

可以考虑C++局部使用

团队能力

大胆用

先培训再上


用C++的正确姿势(别做傻事)

如果决定用C++,有些红线千万别踩:

1. 关掉你不用的特性

CXXFLAGS += -fno-exceptions -fno-rtti -fno-threadsafe-statics CXXFLAGS += -ffunction-sections -fdata-sections LDFLAGS += -Wl,--gc-sections

关掉异常和RTTI,这两个是C++运行时开销的主要来源。在嵌入式里,你不需要它们。

2. 不在堆上分配关键资源

// 可以——在嵌入式里用new的问题不是new本身,是碎片化auto*buf=newuint8_t[1024];// 在初始化时一次分配// 不要频繁new/delete// 更好——栈分配uint8_tbuf[1024];// 更好——静态分配staticuint8_tbuf[1024];

3. 用RAII管理硬件资源

这是C++对比C最大的优势:

classGpioOutput{GPIO_TypeDef*port;uint16_tpin;public:GpioOutput(GPIO_TypeDef*p,uint16_tpi):port(p),pin(pi){// 构造函数里初始化port->CR|=pin;// 配置为输出}~GpioOutput(){// 析构函数里清理port->CR&=~pin;port->ODR&=~pin;// 拉低}voidset(boollevel){if(level)port->ODR|=pin;elseport->ODR&=~pin;}};// 使用——即使异常返回,GPIO也会被正确清理voiddoSomething(){GpioOutputled(GPIOA,GPIO_PIN_5);led.set(true);// 函数退出时,led的析构函数自动执行}

这不仅仅是"语法糖"。RAII让嵌入式代码的资源泄露问题从"runtime bug"变成了"compile-time guarantee"。

4. 模板生成代码,但要关注代码膨胀

// 好的模板用法——编译期计算出常量template<intN>constexprintfactorial(){static_assert(N>=0&&N<=10,"Don't blow up the binary");returnN*factorial<N-1>();}// 不好的模板用法——为每个类型生成一份代码template<typenameT>Tmax(T a,T b){returna>b?a:b;}// 如果你给int、float、double都调用了,就会生成三份代码

对于内存受限的嵌入式设备,模板要节制使用。好在现在有__attribute__((cold))和LTO来帮助压缩。


最后说一句

我对C++进嵌入式的态度一直是:别为了用C++而用C++,但也别因为"别人说不行"就不用。

我职业生涯最大的两次技术债务,都是"因为团队觉得C++太复杂,所以坚持用C"造成的——

第一次是一个LED控制器的固件,用C写到最后25000行,一个static函数调另外13个static函数,没有任何封装,任何一个人改代码,另外三个人需要rebase。

第二次是一个工业协议栈,用C写了6万行,宏定义套宏定义,void*指针满天飞。后来重构时,有C++经验的人用模板+策略模式把核心逻辑从6万行压缩到了2万行,bug率直接降了一个数量级。

语言不是银弹。但选错语言的代价,往往在项目第三年才显现出来——那时候你已经来不及换了。

所以我的建议很简单:

  1. 10万行以下的项目,随便你用C还是C++,都能做出来。
  2. 10万行以上或者需要长期维护的项目,认真考虑C++
  3. 不管用什么语言,团队能力永远是第一位的。
  4. 别跟风,但也别守旧。
http://www.jsqmd.com/news/1209656/

相关文章:

  • 2026甄选:老房地面翻新专业服务公司实力解析 - 甄选服务推荐
  • 基于SpringBoot的社区优选商城(Java+SpringBoot+MySQL)| 计算机毕业设计 附源码论文PPT
  • 2026广州漏水维修处理攻略|厨卫、阳台、外墙、屋顶与地下室处理|常见漏点处理及服务选择 - 盛隆防水
  • 印度理工海德拉巴分校揭示多模态大模型的视觉调度秘密
  • 鸿蒙 ArkTS 实战:Interview Simulator 从轻量生成到草稿管理完整解析
  • OpenAI是否重返机器人赛道?事实核查与技术趋势分析
  • 2026广州漏水维修实用攻略|厨卫、阳台、外墙、屋顶与地下室处理|靠谱防水门店怎么选 - 盛隆防水
  • 劳力士官方售后服务中心地址及客服服务电话实地考察报告_多信源验证(2026年7月最新) - 劳力士服务中心
  • Claude Code本地部署全指南:Node.js+Git+VS Code三步打通AI编程通路
  • 积家中国官方售后服务中心|服务电话及24小时维修地址权威信息公告(2026年7月最新) - 积家官方售后服务中心
  • Matlab版AdaBoost及其特征选择改进算法合集(含训练测试脚本与可视化工具)
  • 2026深圳搬家怎么收费多少钱?全国连锁及本土老牌正规搬家公司报价全解析 实用省钱攻略+避坑指南 专业搬家服务商甄选 - 厚道搬家
  • 正规流量卡在哪里领?2026 四大运营商官方授权流量卡领取入口详解!全网唯一正规手机卡办理渠道、领取方法、避坑大全 - 172号卡
  • 2026 年新发布:江阴评价高的 微型钢管桩订制厂家选哪家,颠覆想象:这小家伙如何解决超高强度地基难题? - 鉴选官
  • 奥地利与维也纳工业大学如何让机器自动编写人类可读“行事准则“
  • 嵌入式Linux驱动调试:printk的9个高阶用法,最后一个是救命级
  • 微信小程序毕业设计:睡眠助手系统(含Java后端源码、开题报告、答辩PPT与操作演示视频)
  • 芜湖车灯升级首选:启恒灯改深度测评12 年本地老店凭什么成为车主公认的靠谱选择 - 优企甄选
  • Web项目线上部署的本质:从环境鸿沟到Docker化工程实践
  • 【双一流高校主办、EI快稳检索】第五届图像处理、目标检测与跟踪国际学术会议(IPODT 2026)
  • 2026年7月最新佛山百达翡丽官方售后客户服务热线与维修网点地址汇总 - 百达翡丽官方售后中心
  • 如何快速获取官方教材PDF:tchMaterial-parser的完整操作指南
  • 腾讯混元推出“又快又强“的轻量级文字识别大模型HunyuanOCR-1.5
  • VR-Reversal:基于MPV+Lua的实时3D VR视频转2D播放方案
  • 词袋模型与 CountVectorizer:文本也可以做特征表
  • MATLAB版车牌识别全流程工程:从图像读取到字符分类,含BP网络训练与实测样本
  • Arduino Leonardo做的双旋钮+十四键音游控制器,即插即用支持多平台
  • 基于小程序云开发与Node.js的餐饮行业AI优化方案:智能推荐与订单预测实战
  • Arduino用RGB点阵屏驱动方案:支持滚动字幕、GIF播放与双缓冲动画
  • 2026年7月最新亨得利官方服务项目及价格查询|电话及服务网点地址权威信息声明 - 亨得利官方博客