拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Keil内置Templates模板:文件头与函数注释一键生成的实用指南

Keil内置Templates模板:文件头与函数注释一键生成的实用指南

先讲个真实经历。前阵子帮同事Review代码,打开他新建的bsp_uart.c,文件头注释是从另一个工程直接复制过来的,里面文件名写着bsp_i2c.c,日期停在三个月前。这个同事不是不认真,他每天写代码很勤快,就是每次新建文件时都靠手动改注释,改着改着就漏了。后来我把Keil自带的Templates功能给他配好,他用了两天就跟我说,这玩意怎么没早点知道。

做嵌入式开发这么多年,Keil uVision4、uVision5都用过,STM32、GD32这些主流MCU的开发也离不开它。我发现大部分开发者对文件头和函数注释的态度都是“知道重要,但懒得维护”。原因很简单:手动敲注释太反人类了。这篇文章我打算把我在Keil里配置文件头注释、函数注释的整套方法写出来,包括字段怎么设计、模板怎么写、调用时按哪个快捷键、中文乱码怎么避免、团队怎么统一这套规范,全部是实操经验,你可以直接照抄。

1. 文件头注释这件小事,为什么总被搞砸

1.1 不是开发者不爱写,是“手动维护注释”这件事反人性

绝大多数嵌入式工程师不是不想写文件头注释,而是手动维护注释的代价太高。文件头需要包含文件名、作者、日期、版本、修改记录,这些信息本身就属于“高频变动、低频回忆”的类型。刚新建文件时还记得填,等调完一个Bug,想顺手在修改记录里加一行,这时候往往已经忘了文件头长什么样,还得翻回文件顶部去对格式。

更麻烦的是,每个工程的模板风格可能还不一样。有的公司要求版权声明,有的要求作者工号,有的要求固件版本号。一旦这些格式细节需要靠人的记忆去维持,出错的概率就非常高。我见过一个工程里五个源文件,文件头注释五种对齐方式,有的用Tab缩进,有的用空格,右边界参差不齐,一眼看过去就知道这个工程经历了不止一任开发者。

这个问题本质上不是“态度问题”,而是“工具问题”。如果注释的插入可以做到像按一个快捷键那么简单,谁都不会拒绝写。你让开发者每天花几十秒去敲注释,一次两次可以,时间一长,优先级肯定排到“赶紧把代码跑通”后面。

1.2 最常见的三种错误做法,看看你中招没

第一种是“复制粘贴改一改”。从老工程复制文件头,改一下文件名和日期就完事。这个方案最大的问题是有“惯性残留”,复制十次可能有一次忘了改作者,文件名对应不上的情况在多人协作的工程里太常见了。我Review代码时经常看到文件头写的是别的模块的名字,这种错误对代码运行没影响,但在产品审计、问题回溯时会带来很大的干扰。

第二种是“用现成的注释插件”。网上确实能找到一些支持Keil的注释增强工具,但这类工具在uVision上的兼容性参差不齐。有的只支持某个特定MDK版本,MDK一升级就失效;有的换台电脑配置就丢了;还有的会和输入法冲突,输入中文时把插件弹窗带出来。说白了,为了一个注释功能引入一个黑盒插件,性价比不高。

第三种是“干脆不写”。这就不用多分析了,评审被打回重写是小事,等过两个月你自己回头看这段代码,才明白文件头那几行字有多值钱。我可以明确说:不写注释省下的三分钟,会在未来用三十分钟甚至更久来偿还。

1.3 思路转变:模板化才是解药

我后来想明白一件事:写文件头注释这个动作,应该被拆成“搭格式”和“填内容”两步。搭格式是重复劳动,交给模板;填内容是创作劳动,交给人脑。模板化之后,每个人的文件头都是一样的骨架,只有日期、作者、描述这些信息不同。代码评审时看到的是统一的风格,追溯问题时也能快速找到对应字段。

这就像快递员寄包裹,面单是系统打出来的,收件人地址和电话由人来填,谁也不会去手画一张快递面单。Keil的Templates功能做的正是这件事,而且它就在你天天打开的IDE里,不需要额外装任何东西。

2. Keil自带Templates功能:最值得优先用的注释方案

2.1 配置入口与基本操作路径

以我常用的uVision 5 MDK为例,Templates功能的配置入口在Edit菜单下的Configuration(配置)对话框里,打开后切到Templates页签,就是模板管理界面。界面上会列出当前已有的模板,左侧是模板列表,右侧是模板正文编辑区。不同版本的MDK或C51菜单文字可能略有差异,但大体的路径和界面逻辑是一致的。

还有一种更快的验证方式:在代码编辑器窗口里右键,菜单里通常能看到Insert Template(插入模板)或Templates子项。如果你能在右键菜单里看到它,说明这个版本支持模板功能。我身边有人用uVision好几年都没点开过这个菜单,第一次看到的时候还挺惊讶的。如果你用的版本菜单布局不太一样,直接到Edit菜单下找Configuration或者Preferences,里面一定有模板相关设置。

2.2 模板的工作原理:触发词加一键展开

Templates功能的原理其实很简单,它就是一种“快捷短语”:你给一段文本定义一个触发词,比如file_head,之后在代码编辑器里输入这个触发词,再按一下快捷键,整段模板文本就会自动替换到光标位置。这个快捷键因版本而异,我用的版本是Ctrl+Shift+Space,你可以在Edit菜单的Shortcut Keys里查一下Insert Template对应的按键绑定,确认自己环境里到底用哪个组合键。

这个机制最大的优势是“所见即所得”。模板正文里怎么排,插入到代码里就是什么样,没有花哨的宏,不需要写脚本,用最朴素的文本替换解决了最实际的痛点。对于大部分嵌入式场景,这个简单机制已经足够了。你不要觉得它不如某些IDE的代码片段(Snippet)功能强大,在Keil这个生态里,稳才是第一位的。

2.3 为什么优先用内置功能,而不是安装第三方插件

我在不同电脑上折腾过多种注释方案,最后留下来的就是Keil内置的Templates。原因是它有几样东西是插件替代不了的:

第一,内置于开发环境,不依赖外部进程,编译、调试、编辑都不会受影响。用外部插件时,经常要担心插件进程崩溃会不会把IDE一起带崩,或者说插件更新后兼容性出问题。

第二,配置所见即所得,改模板就是编辑文本,不需要学插件的配置语言。很多插件的配置文件是XML或者JSON,写错了排查半天,得不偿失。

第三,模板文本是纯文本,复制出去就能分享,不存在“这台电脑能用、那台电脑失效”的问题。你不需要在每台电脑上重新安装插件,只需要把模板文本贴过去。

当然,内置模板也有短板,比如不支持自动填充当天日期、不支持读取文件名自动生成。但这些短板通过简单的模板字段设计,基本都能绕过去,后面我会具体讲。

3. 文件头注释模板从零配置:字段、写法和调用

3.1 一套经过实践的文件头模板字段设计

先给出我目前在用的文件头模板本体。新建一个.c源文件或者.h头文件,插入后只需要改描述、日期、修改记录这几处:

/********************************* Copyright ******************************* ** 文件名 : main.c ** 作者 : YourName ** 版本 : V1.0.0 ** 日期 : 2025-06-01 ** 功能描述: 工程主函数入口,完成系统时钟配置和主循环调度 ** 修改记录: 2025-06-01 建立工程,首次提交 ** 2025-06-05 修复串口初始化顺序导致的乱码问题 *****************************************************************************/

设计这套字段时,我刻意保留了四个核心信息:文件名、作者、版本、日期,外加一个“修改记录”。修改记录这个字段很多人觉得麻烦,我反而认为它是文件头里含金量最高的部分。它记录的不是“改了什么代码”,而是“这个文件的演进轨迹”。在排查线上问题时,修改记录能快速帮你圈定引入Bug的时间段——如果某段功能是V1.2版本加入的,而问题集中出现在V1.2之后,那排查范围一下子就缩小了。

3.2 把模板放进Templates的具体步骤

在Configuration的Templates页签里新建一个模板,触发词填file_head,然后把上面这段文本粘贴到模板正文区保存。之后新建一个.c文件,输入file_head四个字母,按快捷键触发,就能看到文件头模板完整插入,光标停在代码区起始位置。

具体操作顺序可以这样记:

  1. 打开Edit -> Configuration,切到Templates页签。
  2. 点击Add New Template。
  3. 在模板属性里填写触发词file_head。
  4. 把模板正文粘贴到编辑区。
  5. 确认保存,关闭对话框。

关键点是触发词别起得太长,也别和代码里的变量名冲突。file_head这样的命名就很好,不容易误触发,输入成本也低。我见过有人给触发词起名“moban0001”,这种名字你根本记不住,时间一长又回到手动敲注释的老路上去了。

3.3 关于“插入后光标自动定位”的经验

有些版本的Keil模板正文里如果包含一个单独的光标符号,插入后会自动把光标停到那个位置。以我用的MDK版本来说,可以在模板里用竖线|作为光标占位符。比如模板里这样写:

** 功能描述: |

插入后光标会停在竖线处,直接就能开始填功能描述,不需要用方向键去找。如果你的版本不支持竖线占位,也不要纠结,插入后手动跳两下行数,也就一秒钟的事。

还有一个细节是,如果你希望插入模板后自动换行到下一行开始写代码,可以在模板末尾加一个回车。这个要看你自己习惯,我习惯模板尾部带一个空行,插入后直接就能在文件头下面写include或者宏定义。

3.4 模板里要不要写死日期和作者

我的建议是:作者可以写死,日期不要写死。作者通常是固定的,直接在模板里写好能省事;日期是变量,每次新建文件都需要改成当天日期。有些同事问我能不能让模板自动带出当天日期,实话实说,Keil内置模板没有这个能力,除非借助外部工具链。

我的处理方法是:模板里写一个YYYY-MM-DD的占位格式,插入后顺手改掉,手速快一点十秒内搞定。如果要支持自动更新日期,可以配合Python写个小脚本,在新建文件时自动生成带日期的文件头,但这属于另一套方案了。对于大多数团队,内置模板加手动改日期,已经足够舒服。

4. 函数注释模板:给每个函数贴上“身份信息”

4.1 函数注释的信息边界:写什么,不写什么

文件头解决的是“这个文件是干什么的”的问题,函数注释解决的是“这个函数怎么用”的问题。我看到的函数注释经常有两个极端:要么只写一行函数名,等于没写;要么把函数体里每一行代码都翻译成注释,啰嗦且脆弱,代码一改注释就过期。

我常用的函数注释信息边界是:

  • 函数功能:一句话说清楚这个函数干嘛的。
  • 入参:逐个说明含义和范围。
  • 返回值:说明正常返回和异常返回分别是什么。
  • 注意事项:写清楚调用约束,比如是否必须在中断外调用、是否占用不可重入资源、是否需要先初始化某个外设。

至于函数内部怎么实现的,那是代码本身和行内注释的事,不该出现在函数头里。函数头写太多实现细节,反而会让使用者在调用时抓不住重点。

4.2 在Templates里配置一个函数注释模板

在Templates里再新建一个模板,触发词用func_head,模板正文如下:

/** * @brief 函数功能简述 * @param[in] arg1: 入参说明 * @param[out] arg2: 出参说明 * @return 返回值说明 * @note 调用约束和注意事项 */

在需要写注释的函数定义上方输入func_head触发,就会得到这个骨架。然后把arg1、arg2等替换成该函数真正的参数名和说明。这套格式类似Doxygen风格但又不过度复杂,团队评审时看着很清楚。我选择Doxygen风格而不是纯中文格式,是因为它把参数分成了in和out,这对理解调用关系很有帮助。

4.3 更进一步的懒人方案:函数定义也一起模板化

注释模板解决完之后,我顺手把函数定义也做了一个模板,触发词起名func_def:

void 函数名(void) { }

插入后先改函数名,再把(void)里的参数补上,函数体大括号已经在模板里,不会出现少写一个}的尴尬。这个模板配合func_head使用,写一个新函数的完整流程变成:触发func_head填注释,触发func_def填函数骨架,总共不到一分钟。

有人可能会觉得这样太机械,但机械带来的是“稳定”:函数风格统一,缩进统一,花括号成对出现,代码评审的时候大家不用花精力在“这个人喜欢把大括号放哪行”这种问题上争来争去。代码评审应该关注逻辑,而不是格式。

4.4 为什么带标记的注释风格适合团队

上面那套带@brief、@param、@return的注释格式,很多从MCS51时代过来的老开发可能不习惯,觉得不如传统的块注释顺眼。但我实测下来,这种格式对团队协作很友好:信息项是固定的,每个人写出来的注释结构一样,用脚本扫描、用IDE悬停提示都更方便。

如果你觉得带符号的格式太重,把那些@符号换成中文关键字也行,比如“功能:”“入参:”“返回:”“注意:”。关键是要“字段固定、顺序统一”,而不是每个人的注释随心所欲。模板的职责就是把这个“固定和统一”固化下来,让团队所有成员在起点上就是一致的。

5. 模板配置路上的四个坑,我替你踩过了

5.1 中文乱码:最大的隐形杀手

这是我最先踩到的坑。从Word或网页里复制一段带中文的模板正文,粘到Templates配置页,界面里看是好的,关闭再打开工程文件,模板里的中文变成了一堆乱码。Keil对文本编码的处理比较特殊,直接粘贴富文本内容时容易带上不可见字符,或者被转成非UTF-8编码。

解决办法不复杂:如果要在外部编辑模板,先把内容复制到记事本里,转成纯文本,确认编码为UTF-8(某些旧版本用ANSI也没问题),再粘贴进Keil的模板正文区。最稳妥的做法是直接在模板正文区里输入中文,不经过外部复制粘贴。如果你非要从IDE外部粘贴,就先把内容在记事本里转一圈,再复制,能规避大部分乱码问题。

5.2 Tab键导致的对齐灾难

文件头注释的右边界要对齐,靠的是空格数量,而不是Tab。因为Tab宽度在不同编辑器、不同显示设置下完全不一样,你电脑上对齐了,同事电脑上显示全是歪的。我自己有一段时间被这个折磨得不行,后来统一把所有模板里的缩进换成4个空格,问题就消失了。

这里特别提醒一点:如果模板里有中文和英文混排,光靠普通空格很难把右边界完全对齐,因为中文是全角字符,英文是半角字符,视觉宽度不一样。这种情况下,可以考虑用全角空格来补足宽度。注意别在全英文的纯代码模板里用全角空格,那会导致编译问题,但在注释区域里用没关系。

5.3 团队模板同步:别靠U盘和微信传文件

模板配置本身不长,但如果团队有五个人,每个人都自己配一遍,最后一定是至少有两个人配出来的格式不一样,然后评审时吵起来。我在团队里做的很简单:把文件头模板和函数注释模板的文本放在Git仓库的docs目录下,命名为CodeTemplate.md,里面写好配置步骤。任何人新装开发环境,打开这个文件,照着复制粘贴一遍,两分钟就配好。

模板的准确来源只有仓库一份,避免“每个人手里一个新版本”的混乱。如果你是用subversion或者干脆用共享文件夹的团队,逻辑也是一样的,核心思想就是“模板的源只有一处,所有人从这一处获取”。

5.4 格式化工具和模板的顺序问题

有人喜欢在Keil里挂外部格式化工具,比如Astyle。这里提醒一个顺序问题:先统一注释模板,再上自动格式化。Astyle本身默认不会删除标准块状注释,包括文件头和函数头,但如果你的注释格式本身就乱,比如有的行用//、有的行用/* */且缩进不统一,Astyle跑完会产生一堆奇怪的换行和对齐错误。

正确的做法是:先把模板统一成上面说的格式,让所有源文件都按同一套注释骨架生成,然后再用Astyle做代码缩进整理。顺序反了,你会得到更差的体验。换句话说,格式化工具是“规范放大器”——基础规范你做好了,它给你锦上添花;基础规范你做得稀烂,它给你把问题放大。

6. 我现在的注释工作流与最后的习惯建议

6.1 完整工作流:新建文件到函数完成,全程不碰格式

我现在的工作流是这样的。新建一个bsp_led.c源文件,第一件事输入file_head触发文件头模板,改一下文件名和日期,填一句功能描述;接着写函数,在函数定义之前输入func_head触发函数注释模板,填好入参、返回值和注意事项;再输入func_def生成函数骨架。这些动作加在一起,一个文件从无到有的固定开销也就是两三分钟,大头还是花在写业务逻辑上。

这个流程跑顺之后,你写注释的阻力会变得非常小。原来可能是“写完代码再补注释”,现在变成了“在建文件、写函数的瞬间顺便把注释填了”。这个顺序的改变很重要,因为“事后补注释”很容易变成“事后不补注释”。

6.2 让模板成为团队基础设施,而不是个人技巧

如果你的代码会被别人Review,或者工程会交接给下一个工程师,我强烈建议把模板这件事上升为团队基础设施。它不需要是强制制度,但需要在文档里写得足够清楚。新同事入职第一天,给他指一下CodeTemplate.md,配好模板,他写出的第一个文件就不会犯“注释格式和组里老工程不搭”的毛病。

我在实际带人的过程中发现,模板化对新人尤其友好。新人最怕的不是不会写代码,而是不知道团队默认的规矩是什么。你把模板给他,等于把“文件头必须包含哪些字段”“注释用什么格式”这些隐性规矩变成了显性工具。他不需要记住规则,只需要用工具。

6.3 我的一点真实体会

最后说点实在的。注释模板这个东西,看起来只是省了几分钟敲键盘的时间,但它真正的价值在于:它逼着你在建文件、写函数的瞬间,用一句话把这个文件或函数的职责说清楚。如果你说不清楚,那大概率是设计还没想清楚。对我来说,这个习惯比省下的时间值钱得多。

这套方法没有高深技术,全是朴实配置,但一个长期被注释问题烦恼的Keil开发者,花二十分钟把模板配好,之后每一次新建文件、每一次写函数,都会感受到这一点点便利的复利。如果你身边还有同事在靠复制粘贴维护文件头,把这篇文章转给他,省他几个月的手动劳动,这比什么都实在。

返回列表