现代C:生产加速:C 项目需要考虑的编码规范有哪些? 引言在本模块前面的几讲中我主要介绍了可以为项目编码提速的 C 标准库以及优化 C 代码的相关技巧。而在接下来的三讲中我将为你介绍大型 C 项目在工程化协作时需要关注的编码规范、自动化测试和结构化编译。当项目由小变大参与人数由少变多时这些便是我们不得不考虑的重要内容。和一个人参与项目、写代码时的“单打独斗”相比多人协作从理论上来看可以大幅提高生产效率。但现实情况却可能是效率在提升的同时代码质量下降、沟通成本变高等一系列问题也随之而来。甚至在某些情况下团队人数的增加反而会导致项目推进效率的降低。那为什么会出现这样的问题呢这是因为当参与到项目开发中的人员数量逐渐增多时工程师们对于代码编写规范以及项目开发生命周期SDLCSoftware Development Life Cycle等关键事项没有形成统一的标准。而因为代码审查不通过导致的频繁返工甚至妥协以及协作流程上的不明确与延期使得项目的迭代周期变长进而生产效率下降。因此如何为团队制定统一的编码规范并明确 SDLC 的整体流程以及其中各节点的重点注意事项就成为了决定团队协作效率的一个重要因素。那么这一讲我们就来聊一聊对于使用 C 语言编写的、需要多人协作的项目我们应该从哪些角度来制定团队的编码规范。这里我会以 GNU C 编码规范为例来进行介绍在此之前我们先来看看什么是 GNU。GNU 与 GUN傻傻分不清楚你应该对 GNU 这个由三个英文字母组成的标识并不陌生虽然有时我也会把它与“文明用语” GUN 搞混。不过你可能还不清楚它实际上是 GNU’s Not Unix 的递归首字母缩写词而且读音类似于中文“革奴”的发音。具体来讲GNU 最初是指由 Richard Matthew Stallman 于 1983 年创立的一项计划该计划旨在创建一套完全自由的操作系统和相关系统软件的集合。该计划执行至今除了仍然处在开发阶段的 GNU 操作系统内核 Hurd 以外其他相关系统软件都已经得到了社区的广泛应用。其中不乏我们熟知的 GCC 编译器、GDB 调试器以及 Emacs 文本编译器等。目前截止到 2022 年 1 月一共有 384 个 GNU 软件包被托管到 GNU 的官方开发站点上。其中GCC 和 GDB 的第十二个大版本也处在紧张的开发过程中。当年发起 GNU 计划的一个初衷是让业界重视软件界合作互助的团结精神而在经过了将近 40 年的发展后这一精神可以说在 GNU 旗下的项目上被体现得淋漓尽致。以 GCC 为例就该项目而言被正式记载到官方贡献者列表中的开发者就超过了 500 人。而如果将它的 Git 仓库下载下来并通过相关命令统计所有提交过代码的贡献者人数根据邮箱区分这个数字将高达 3500。由此可见GCC 作为 GNU 旗下使用人数最多的开源项目之一它能够一直以来被社区广泛采纳除了源于自身极高的项目质量外也离不开贡献者之间默契的协作其中就包括在编码规范上的统一。为了保证 GNU 旗下的开源项目都能够采用统一的代码格式Richard Stallman 和一众来自 GNU 开源项目的志愿者从 1992 年起便开始着手制定一套统一的编码规范GNU Coding Standards后简称“GNU 编码规范”。制定这套编码规范是为了保持 GNU 操作系统以及相关软件有干净、一致的编码风格并保持足够高的可移植性与可靠性。这套编码规范更适用于 C 语言编写的程序但其中的许多规则与原则也同样适用于其他编程语言。接下来我们就以 GNU 编码规范为例来看一看围绕 C 语言项目制定编码规范时具体都需要考虑哪些方面。在充分了解这些内容后你就可以根据自己团队与项目的情况来选择性制定更加合适的编码规范了。GNU C 编码规范GNU 编码规范将 C 语言项目需要考虑的编码细则分为了多个不同类别下面我们来依次看看这些内容中最常用的 9 个方面。格式这一类别中的规则主要约束了 C 代码的具体编写格式。比如GNU 规范建议将每一行代码的字符数量保持在 79 个以内以便在大多数情况下获得最好的代码可读性C 函数定义时使用的开始花括号 “{” 建议作为每行的第一个字符这样有助于兼容大多数代码分析工具。而类似地为了更好地识别函数定义函数名称同样需要放置于每行的起始位置同时也利于某些特定工具对函数的识别。除此之外在函数定义或声明中若函数参数过长则需要将超过行长度限制的参数放到函数名所在的下一行并与上一行中第一个参数的开头保持对齐。而对于结构或枚举类型可以选择在符合行长度限制的情况下将它们在一行内完整定义。或采用类似函数的定义方式将包裹定义的开始与结束花括号放置在单独一行两行之间为具体的定义内容。你可以看下这个例子它便符合我在上面提到的几点 GNU 编码规范对代码格式的要求int lots_of_args (int an_integer, long a_long, short a_short, double a_double, float a_float) { // ... } struct foo { int a, b; } struct bar { int x, y; }这里我们提到的仅是一些较为重要的代码格式化规则但除此之外还有很多其他 GNU 代码格式要求的规范细节。关于这些内容你可以参考 GNU 旗下的 indent 工具。这个工具提供了多种不同选项可以对 C 源代码应用多种不同的代码格式化风格你可以点击这个链接来了解这些信息。这些风格主要针对缩进、括号以及换行等字符或语法元素在特定代码场景中的不同使用方式。但无论哪种方式你都需要确保在同一个 C 项目中仅使用唯一的一种风格规则来格式化你的代码。注释注释的用途显而易见。一个优秀程序的最基本特征就是可以让任何一个工程师都能在最短的时间内了解这个程序的基本实现逻辑。而注释就是达成这一目的的“秘密武器”。在文件方面GNU 规范建议程序 main 函数所在源文件应以描述程序基本用途的注释作为开头而其他源文件则以文件名和描述该源文件基本功能的注释作为开头。对于函数则需要为其添加用于描述函数基本功能、参数类型、参数用途、参数可能取值以及返回值含义如果有等内容的注释信息。对于每一个全局和静态变量也应该为其添加相应的注释来描述它们的基本用途与可能取值。除基本 C 语法代码外诸如预处理指令 #else 与 #endif 也需跟随有相应的注释以标注相应分支的位置和含义。一般情况下为保证国际化和通用性应以英语形式撰写注释。若代码与注释在同一行则注释应起始于该行代码最后一个字符后间隔两个空格的位置。注释应使用完整的句子并在一般情况下保持首字母大写。最后需要注意的是若在注释中谈论到了变量的值则应将该变量对应标识符完全大写。比如在注释文本“the inode number NODE_NUM” 中提到的 NODE_NUM 便代表 C 代码中变量 node_num 对应的具体值。语法约定这部分规范对 C 语言编码时需要遵循的一些基本习惯作出了规定。这里举几个例子显式地为所有使用到的值标注类型尤其是直接使用在表达式中的数字字面量值选择性地为编译器添加 “-Wall” 参数并根据警告信息来优化代码选择性地看待静态代码分析工具给出的建议在不影响程序正常功能的情况下不要为了满足它们的要求而牺牲代码可读性外部函数和后续才会使用函数的声明应该被放置在当前源文件开头处统一的地方或选择放在单独的头文件中使用名字具有一定意义的不同变量来完成不同任务且尽量使变量的声明处在恰好可以完成其“任务”的最小作用域中。除此之外也不要声明会遮盖全局变量的局部变量。在代码写法上GNU 代码规范也作出了规定比如不要将通过一个类型关键字声明的多个变量分散在多行可以将同类型的多个变量放在同一行声明或选择在不同行使用独立的声明语句来声明多个变量当使用嵌套的流程控制语句比如 if 语句时总是将内部的嵌套逻辑包裹在大括号中以保证代码清晰可读尽量避免在 if 语句的条件判断处也就是小括号内部做赋值操作而在 while 语句中是可以的。命名编码中的命名规范可以说是理解起来最简单而行动上最复杂的部分。在 C 语言项目中程序内使用到的全局变量和函数它们的名称有时可以直接替代注释来说明它们的功能。因此需要确保对于它们的命名是具有一定意义的。而相对地局部变量由于仅作用在一个较短的上下文中它的名字可以更短只要能大概描述它的作用即可。变量名一般采用下划线命名法即通过下划线将其中不同的单词进行分割。变量名中可以使用缩写但需要确保这些缩写是已经被人们熟知的而不会产生任何歧义。并且尽量仅使用小写字母、数字和下划线来组成变量名而把大写字母留给对宏常量以及枚举常量命名。另外当需要定义数字常量值时请优先使用枚举常量而非宏常量这将有利于调试器对程序执行逻辑的分析。比如下面这段代码enum Settings { LIMITATION 1000 }; const char* author_name Jason; const int author_age 28;系统可移植性GNU 规范中提到的“系统可移植性”主要是指将 C 应用移植到不同 Unix 版本系统上的能力。对于 GNU 程序来说这种可移植性是可取的但并非最重要的。通常来说你可以直接使用 GNU 旗下的 Autoconf 工具来部分实现这种能力。Autoconf 支持多种 Unix 系统它可以根据当前所在宿主环境自动生成进行程序编译所需的配置文件比如 Makefile 与 configure 脚本文件。对于其他非 Unix 系统则需要针对目标系统做特殊的兼容性开发。除此之外在程序中应该尽量使用来自标准库如 C 标准库、POSIX 标准接口等中的函数而非与特定系统强相关的底层能力。最后可以选择为 C 语言项目定义名为“_GNU_SOURCE” 的宏常量当在 GNU 或 GNU/Linux 系统上编译定义有该宏常量的 C 项目时预处理器会“启用”所有的 GNU 库扩展函数。这样编译器在编译项目时便会及时检查是否存在用户的自定义函数导致这些库函数被覆盖的问题。在保证程序系统兼容性方面这是可以关注的一个点。CPU 可移植性不同 CPU 之间可能会存在着字节序、对齐要求等差异。因此我们在编码时不应该假设一个 int 类型变量在内存中的起始地址与它的最低有效位LSB地址相同。同样地当使用 char 类型时应显式指出它的符号性。对于指针应尽量避免出现将指针类型转换成数字值的过程以保持程序最大的兼容性。对于基本类型大小GNU 标准不会处理 int 类型小于 32 位的情况。同样也不会考虑 long 类型小于指针类型和 size_t 类型的情况。系统函数C 程序可以通过调用 C 标准库或 POSIX 库提供的函数来使用相应的系统功能但这些库函数在某些系统上可能存在着相应的可移植性问题。而借助 Gnulib我们可以在一定程度上解决这个问题。Gnulib 是 GNU 旗下的可移植性库它为许多缺乏标准接口的系统提供了对标准接口的实现其中包括对增强型 GNU 接口的可移植性实现等。Gnulib 可以直接与 GNU Autoconf 和 Automake 集成使用来减少程序员编写可移植代码时的大部分负担。Gnulib 使得我们可以通过配置脚本来自动确定缺少哪些功能并使用 Gnulib 中的代码来“修复”缺少的部分。国际化GNU 规范也考虑到了 C 程序国际化的问题。同解决系统函数可移植性问题一样GNU 也提供了名为 GNU gettext 的库可以轻松地将程序中的消息翻译成各种语言。字符集在 GNU 源代码注释、文本文档以及其他相关上下文中请首选使用 ASCII 字符集中的字符。如果需要使用非 ASCII 字符我们要确保文档的编码方式保持统一。通常来说UTF-8 应是首选的编码方式。总结好了讲到这里今天的内容也就基本结束了。最后我来给你总结一下。这一讲我以 GNU 编码规范为例介绍了在进行 C 项目编码时我们需要注意的几方面内容。从最基本的编码格式到可能影响程序正确运行的可移植性这些内容涵盖了一个完整 C 工程项目在制定编码标准时需要考虑的绝大部分问题。GNU 编码规范的出发点是确保所有 GNU 旗下项目都能够采用统一的编码行为以保证这些软件都能够在 GNU 操作系统上正确无误地运行。了解 GNU 规范的基本内容之后你就能以此为基础根据自身需求制定更加详细和个性化的 C 编码规范。编码规范的制定是项目从单人开发逐渐走向多人协作让团队效率达到 112 效果的必经之路。因此如何合理制定规范并加以落实并持续实践是一个非常值得关注的问题。

相关新闻

最新新闻

计算机毕业设计之学生疫情信息管理系统

计算机毕业设计之学生疫情信息管理系统

学生疫情信息管理系统是学校中重要的一环,学生疫情信息管理是教师、学生获取信息的主要渠道。于是经过考虑之后决定开发基于JSP技术设计与实现了一款简洁、轻便的学生疫情信息管理系统。本系统解决了学生疫情信息管理的主要问题,包括以下多个功能模块&am…

2026/7/21 11:05:53
计算机毕业设计之学生选课网站的设计与实现

计算机毕业设计之学生选课网站的设计与实现

教育行业也在不断细化,如今市场上对于在线教育的需求急剧增多,自动化信息处理和基于网络的信息交互方式已被广泛应用。现在学生信息管理基本上都是交由计算机进行管理和选课,高等学校管理已成为整个教育体系中的重要组成部分。虽然信息技术广…

2026/7/21 11:05:53
如何快速获取学术文献PDF:Zotero-SciHub插件的终极解决方案

如何快速获取学术文献PDF:Zotero-SciHub插件的终极解决方案

如何快速获取学术文献PDF:Zotero-SciHub插件的终极解决方案 【免费下载链接】zotero-scihub A plugin that will automatically download PDFs of zotero items from sci-hub 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-scihub 你是否曾经花费数小…

2026/7/21 11:05:53
如何快速搭建Sunshine游戏串流服务器:5步实现跨设备游戏自由

如何快速搭建Sunshine游戏串流服务器:5步实现跨设备游戏自由

如何快速搭建Sunshine游戏串流服务器:5步实现跨设备游戏自由 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 你是否想过在客厅大屏上玩PC游戏,或者在平板上…

2026/7/21 11:05:53
计算机毕业设计之学生信息管理系统设计与实现

计算机毕业设计之学生信息管理系统设计与实现

学生信息管理系统是学校中重要的一环,于是经过考虑之后决定开发基于JSP技术设计与实现了一款简洁、轻便的学生信息管理系统。本系统解决了课程信息的主要问题,包括以下多个功能模块:课程信息、课程选择、课程成绩、奖惩记录、学生学籍、学生请…

2026/7/21 11:05:53
如何在ARM设备上高效运行x86_64程序:Box64终极兼容方案实战指南

如何在ARM设备上高效运行x86_64程序:Box64终极兼容方案实战指南

如何在ARM设备上高效运行x86_64程序:Box64终极兼容方案实战指南 【免费下载链接】box64 Box64 - Linux Userspace x86_64 Emulator with a twist, targeted at ARM64, RV64 and LoongArch Linux devices 项目地址: https://gitcode.com/gh_mirrors/bo/box64 …

2026/7/21 11:00:53

月新闻