资讯动态

CANN hixl 仓库 C++ 代码风格规范实战指南:命名、格式与注释规范全解析

发布时间:2026/9/18 22:00:19 来源:尧图企业网站定制
CANN hixl 仓库 C 代码风格规范实战指南命名、格式与注释规范全解析【免费下载链接】hixlHIXLHuawei Xfer Library是一个灵活、高效的昇腾单边通信库面向集群场景提供简单、可靠、高效的点对点数据传输能力。项目地址: https://gitcode.com/cann/hixl本文以 docs/zh/contributions/coding_standards/cpp-style.md 为骨架系统讲解 CANN 开源社区含 hixl 仓库的 C 代码风格规范。全文覆盖命名、格式、注释三大维度的 20 余条规则与建议并结合仓库根目录 .clang-format 配置与 src/hixl 目录下的真实源码进行印证。读者完成本文后可对照规范自查代码、理解 clang-format 与风格规则的对应关系并能顺利通过 docs/zh/contributions/precommit_guide.md 描述的 pre-commit 代码格式化与合规检查。规范背景与适用范围CANN 的 C 代码风格规范以 Google C Style Guide 为基础参考 MindSpore 社区与华为通用编码规范并结合业界共识整理而成。参与 CANN 开源社区项目包括本 hixl 仓库的开发者首先需要遵循本规范内容其余场景遵循 Google C Style Guide。若对规则有异议可提交 issue 说明理由经 CANN 运营团队评审通过后可接纳并修改生效。规范的适用对象是CANN 相关开源仓的代码风格检视即所有新提交的 C 代码都应满足下表所列的规则。规范按「规则Rule」与「建议Suggestion」区分强制力规则类条目如 1.1、2.2、2.4属于必须遵守的硬性要求建议类条目如 2.1、3.4、3.5属于推荐实践优先级略低但同样应当遵循。规范总览规范编号规范名称类别严重级别1.1C文件使用小写下划线命名命名中1.2函数命名使用大驼峰风格命名中1.3类型命名采用大驼峰风格命名中1.4变量命名采用小写下划线snake_case风格命名中1.5宏、枚举值采用全大写下划线连接命名中1.6编译期常量采用 k 前缀大驼峰命名中2.1行宽不超过 120 个字符格式低2.2使用空格缩进每次 2 个空格格式中2.3、*跟随变量名格式低2.4if 语句必须使用大括号格式中2.5for/while 循环必须使用大括号格式中2.6表达式换行运算符放行末格式低2.7使用附着式Attach大括号风格格式中2.8多个变量定义不允许写在一行格式低2.9合理安排空行保持代码紧凑格式低3.1文件头注释包含版权声明注释中3.2右置注释使用//注释与代码间有空格注释低3.3禁止使用 TODO/TBD/FIXME 注释注释中3.4不要写空有格式的函数头注释注释低3.5不用的代码直接删除不要注释掉注释中1. 命名规范命名风格基础规范中涉及两种基本命名风格驼峰风格CamelCase大小写字母混用单词连在一起不同单词间通过单词首字母大写来分开。按连接后首字母是否大写又分为大驼峰UpperCamelCase和小驼峰lowerCamelCase。小写下划线风格snake_case单词全部小写单词间用下划线连接如table_name。各类符号与命名风格的对应关系如下表类型命名风格类类型结构体类型枚举类型联合体类型等类型定义作用域名称大驼峰函数包括全局函数作用域函数成员函数大驼峰编译期常量constexpr或以字面量/编译期常量表达式初始化的 const含各作用域k 前缀大驼峰全局变量包括全局和命名空间域下的变量类静态变量局部变量函数参数类、结构体和联合体中的成员变量小写下划线snake_case宏枚举值goto 标签全大写下划线分割这里有两点需要特别注意常量的判定标准上表中的「常量」指值在编译期即可确定的 const/constexpr 基本数据类型、枚举、字符串类型的变量constexpr或以字面量/编译期常量表达式初始化的 const含各作用域不包括数组和其他类型变量以函数调用或运行期数据初始化的 const 变量不属于常量按普通变量命名。变量的判定标准除常量定义以外的其他变量均使用小写下划线snake_case风格。规则 1.1 C 文件使用小写下划线命名C 源文件默认以.cpp结尾头文件以.h结尾。业界还存在其他后缀表示方式头文件.hh、.hpp、.hxxcpp 文件.cc、.cxx、.c如果当前项目组已经使用了某种特定后缀例如部分历史工程使用.cc可以继续使用但必须保持风格统一。本规范默认使用.h和.cpp作为后缀。在 hixl 仓库中可以看到两种后缀并存但各自统一的情况src目录下的核心实现以.cc/.h为主如 src/hixl/cs/endpoint.cc、src/hixl/common/hixl_log.h测试目录同样延续.cc如 tests/cpp/hixl/common/thread_pool_ut.cc而 include 目录对外发布的头文件统一使用.h。这正体现了「风格统一」的原则——同一仓库内不混用多种后缀。规则 1.2 函数命名统一使用大驼峰风格函数全局函数、作用域函数、成员函数统一使用大驼峰命名一般采用动词或动宾结构class List { public: void AddElement(const Element element); Element GetElement(const unsigned int index) const; bool IsEmpty() const; }; namespace Utils { void DeleteUser(); }一个重要的例外是实现标准库、第三方库或序列化框架要求的接口契约函数如lock/try_lock/unlock、to_json/from_json等可保留接口要求的原名不受本规则约束。在 hixl 源码中函数命名严格遵守大驼峰如 src/hixl/cs/endpoint.cc 中的InitQueueDepth、BuildChannelName、InitChannelDesc、IsDefaultHostVaMappingEnabled等均为「动词/动宾」或「Is 开头的布尔查询」结构。规则 1.3 类型命名采用大驼峰命名风格所有类型命名——类、结构体、联合体、类型别名using/typedef、枚举——使用相同的大驼峰约定// classes, structs and unions class UrlTable { ... struct UrlTableProperties { ... union Packet { ... // type aliases using PropertiesMap std::mapstd::string, UrlTableProperties *; // enums enum UrlTableErrors { ...命名空间也建议使用大驼峰// namespace namespace FileUtils {}hixl 仓库中大量类型命名遵循此规则例如 src/hixl/common/hixl_inner_types.h 中的EndpointDesc、ChannelDesc、HcommChannelDesc以及 include/hixl/hixl_types.h 中对外暴露的CommProtocol、ChannelType等枚举类型。规则 1.4 通用变量命名采用小写下划线snake_case全局变量、函数形参、局部变量、成员变量均采用 snake_casestd::string table_name; // Good: 推荐此风格 std::string tableName; // Bad: 禁止小驼峰风格 std::string tablename; // Bad: 禁止无单词分隔的风格 std::string path; // Good: 只有一个单词时snake_case 为全小写全局变量应增加g_前缀静态变量命名不需要加特殊前缀。加前缀的目的是在视觉上突出全局变量促使开发人员对这些易出问题的变量使用更加谨慎全局静态变量命名与全局变量相同函数内的静态变量命名与普通局部变量相同类的静态成员变量和普通成员变量相同。int g_active_connect_count; void Func() { static int packet_count 0; ... }类的成员变量命名以 snake_case 加后下划线组成struct 纯数据结构的公共成员可不加后下划线同一结构内保持一致class Foo { private: std::string file_name_; // 类成员添加 _ 后缀区分 }; struct Point { int x; // struct 纯数据成员可不加后缀 int y; };hixl 源码是这一规则的标准范例如 src/hixl/cs/endpoint.cc 中的局部变量is_client、data_depth、channel_name、client_ep、server_ep均采用 snake_case成员变量加_后缀的模式在 src/hixl/cs/channel.h、src/hixl/fabric_mem/fabric_mem_slot_pool.h 等头文件中大量可见。规则 1.5 宏、枚举值采用全大写下划线连接宏、枚举值、goto 标签使用全大写 下划线连接#define MAX(a, b) (((a) (b)) ? (b) : (a)) // 仅对宏命名举例并不推荐用宏实现此类功能 enum TintColor { // 注意枚举类型名用大驼峰其下面的取值是全大写下划线相连 RED, DARK_RED, GREEN, LIGHT_GREEN };注意示例中的细节枚举类型名TintColor用大驼峰而枚举值DARK_RED用全大写 下划线。hixl 中的日志宏即遵循此规范如 src/hixl/common/hixl_log.h 中的HIXL_LOGE、HIXL_LOGW、HIXL_LOGI、HIXL_LOGD、HIXL_EVENT、HIXL_RECORD以及各类检查宏HIXL_CHK_STATUS_RET、HIXL_CHK_ACL_RET、HIXL_CHK_HCCL_RET等。规则 1.6 编译期常量采用 k 前缀大驼峰命名编译期常量constexpr或以字面量/编译期常量表达式初始化的 const不论作用域全局、命名空间、类静态成员、函数局部统一使用k 前缀大驼峰命名int Func(...) { constexpr unsigned int kBufferSize 100; // 编译期常量k 前缀大驼峰 char *buffer new char[kBufferSize]; const int saved_errno errno; // 运行期初始化的 const按普通变量 snake_case 命名 ... } namespace Utils { constexpr unsigned int kDefaultFileSizeKb 200; // 全局编译期常量 }判定要点以函数调用或运行期数据初始化的 const 变量不是常量按普通变量命名规则 1.4类的非静态const 成员变量按成员变量命名规则snake_case 加后下划线命名。hixl 源码中 k 前缀常量随处可见例如 src/hixl/cs/endpoint.cc 中的kRoceQueueNum、kMinTransportQueueDepthsrc/hixl/common/hixl_inner_types.h 中的kProtocolRoce、kProtocolUboe、kRdmaTrafficClass、kRdmaServiceLevel、kDefaultSplitBatchSize、kMaxMultiWorkerNum等。可以看到常量覆盖了数值uint32_t、uint8_t与字符串const char *两类符合规范中「基本数据类型、枚举、字符串类型的变量」的界定。2. 格式规范建议 2.1 行宽不超过 120 个字符建议每行字符数不超过120个。若超过 120 个字符请选择合理的方式换行。允许的例外包括一行注释包含超过 120 个字符的命令或 URL可保持一行方便复制、粘贴和通过 grep 查找包含长路径的#include语句可以超出 120 个字符但应尽量避免编译预处理中的 error 信息可以超出一行保持一行便于阅读和理解。#ifndef XXX_YYY_ZZZ #error Header aaaa/bbbb/cccc/abc.h must only be included after xxxx/yyyy/zzzz/xyz.h, because xxxxxxxxxxxxxxxxxxxxxxxxxxxxx #endif这一限制与仓库根目录 .clang-format 中的ColumnLimit: 120完全一致clang-format 会按此配置自动折行。规则 2.2 使用空格进行缩进每次缩进 2 个空格只允许使用空格space缩进每次缩进为2 个空格不允许使用 Tab 符。当前几乎所有 IDE 都支持将 Tab 自动扩展为 2 空格输入建议配置 IDE 开启该选项。另外命名空间内部不缩进与 .clang-format 的NamespaceIndentation: None一致。对应到 .clang-formatIndentWidth: 2、TabWidth: 2、UseTab: Never。观察 src/hixl/cs/endpoint.cc 的代码namespace hixl {内部顶格书写函数体内容缩进 2 空格控制流嵌套逐级加 2 空格正是该规则的落地效果。规则 2.3、*跟随变量名声明指针、引用变量或参数时、*跟随变量名另外一边留空格char *c; const std::string str;这与 .clang-format 的PointerAlignment: Right对应。规则 1.2 示例中的const Element element即按此写法。规则 2.4 if 语句必须使用大括号即便只有一条语句if 语句也必须使用大括号。理由如下代码逻辑直观、易读在已有条件语句代码上增加新代码时不容易出错对于在 if 语句中使用函数式宏时有大括号保护不易出错如果宏定义时遗漏了大括号。// 即使if分支代码只有一行也必须使用大括号 if (cond) { single line code; }注意clang-format 不会自动为单条语句补全大括号.clang-format 中AllowShortIfStatementsOnASingleLine: true允许单行 if 形式本规则依赖代码检视或 clang-tidyreadability-braces-around-statements保证。规则 2.5 for/while 等循环语句必须使用大括号与条件表达式类似for/while 循环语句必须加上大括号即便循环体是空的或循环语句只有一条for (int i 0; i some_range; i) { // Good: 使用了大括号 DoSomething(); }while (condition) { // Good循环体是空也使用大括号 }注意同规则 2.4clang-format 不会自动为循环语句补全大括号.clang-format 中AllowShortLoopsOnASingleLine: true允许单行循环形式需依靠代码检视保证。规则 2.6 表达式换行要保持一致性运算符放行末较长的表达式不满足行宽要求时需要在适当的地方换行。一般在较低优先级运算符或连接符后面截断运算符或连接符放在行末表示「未结束后续还有」// 假设下面第一行已经不满足行宽要求 if ((current_value threshold) // Good换行后逻辑操作符放在行尾 some_condition) { DoSomething(); ... } int result really_long_variable_name1 // Good really_long_variable_name2;表达式换行后续行与首个操作数对齐与 .clang-format 的AlignOperands: true一致int sum long_variable_name1 long_variable_name2 long_variable_name3 long_variable_name4 long_variable_name5 long_variable_name6; // Good: 续行与首个操作数对齐规则 2.7 使用附着式Attach大括号风格附着式Attach风格所有左大括号包括函数、类、结构体、控制语句等跟随语句放行末前置 1 空格。右大括号独占一行除非后面跟着同一语句的剩余部分如 do 语句中的 while或者 if 语句的 else/else if或者逗号、分号。struct MyType { // 跟随语句放行末前置1空格 ... }; int Foo(int a) { // 函数左大括号同样跟随语句放行末 if (...) { ... } else { ... } }推荐这种风格的理由代码更紧凑相比另起一行放行末使代码阅读节奏感上更连续符合后来语言的习惯符合业界主流习惯与仓库 .clang-format 配置BreakBeforeBraces: Attach一致提交前执行 clang-format 不会产生额外 diff现代 IDE 都具有代码缩进对齐显示的辅助功能大括号放在行尾并不会对缩进和范围产生理解上的影响。对于空函数体可以将大括号放在同一行class MyClass { public: MyClass() : value_(0) {} private: int value_; };查看 src/hixl/cs/endpoint.cc 可以直观看到附着式风格的统一应用bool IsUrmaProtocol(...)左大括号紧跟行末if/else、for等控制结构同样如此} else if、} else的右大括号与后续关键字同行。规则 2.8 多个变量定义和赋值语句不允许写在一行每行只写一个变量初始化语句更容易阅读和理解。规则 2.9 合理安排空行保持代码紧凑减少不必要的空行可以显示更多代码方便阅读。建议遵守以下规则根据上下内容的相关程度合理安排空行函数内部、类型定义内部、宏内部、初始化表达式内部不使用连续空行不使用连续空行最多保留 1 个与 .clang-format 的MaxEmptyLinesToKeep: 1一致大括号内的代码块行首之前和行尾之后不要加空行但 namespace 的大括号内不作要求。int Foo() { ... } int Bar() { // Bad最多保留 1 个连续空行。 ... } if (...) { // Bad大括号内的代码块行首不要加入空行 ... // Bad大括号内的代码块行尾不要加入空行 } int Foo(...) { // Bad函数体内行首不要加空行 ... }3. 注释规范一般的尽量通过清晰的架构逻辑、好的符号命名来提高代码可读性需要的时候才辅以注释说明。注释是为了帮助阅读者快速读懂代码所以要从读者的角度出发按需注释。注释内容要简洁、明了、无二义性信息全面且不冗余。在 C 代码中使用/* */和//都是可以的。按注释的目的和位置注释可分为不同的类型如文件头注释、函数头注释、代码注释等同一类型的注释应该保持统一的风格。规则 3.1 文件头注释包含版权声明每个源文件头部必须包含版权声明示例如下/** * Copyright (c) 2026 Huawei Technologies Co., Ltd. * This program is free software, you can redistribute it and/or modify it under the terms and conditions of * CANN Open Software License Agreement Version 2.0 (the License). * Please refer to the License for details. You may not use this file except in compliance with the License. * THIS SOFTWARE IS PROVIDED ON AN AS IS BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. * See LICENSE in the root of the software repository for the full text of the License. */关于版权年份的写法2026 年新建的文件应为Copyright (c) 2026 Huawei Technologies Co., Ltd.2025 年新建、2026 年修改的文件应为Copyright (c) 2025-2026 Huawei Technologies Co., Ltd.。hixl 仓库的所有源文件均带此版权头例如 src/hixl/common/hixl_log.h 与 scripts/check_log_spec.py 的前 9 行。值得注意的是该文件头是合规检查OAT 扫描的硬性要求——docs/zh/contributions/precommit_guide.md 中明确许可证头缺失或错误会阻止提交必须修复后才能通过 pre-commit 的oat-check。规则 3.2 右置注释使用//注释与代码间有空格代码注释应置于对应代码的上方或右边注释符与注释内容之间要有 1 个空格右置注释与前面代码至少 1 个空格右置注释使用//而不是/**/置于代码上方的注释使用//或/* */均可// this is multi- // line comment int foo; // this single-line comment.clang-format 中的SpacesBeforeTrailingComments: 2保证右置注释前至少保留 2 个空格。源码中该规则的典型应用如 src/hixl/common/hixl_inner_types.h 中的constexpr uint8_t kRdmaTrafficClass 132; // RDMA网卡的traffic class 默认值。规则 3.3 禁止使用 TODO/TBD/FIXME 注释代码中禁止使用 TODO/TBD/FIXME 等注释建议提 issue 跟踪待办事项。这类残留注释会在 pre-commit 流程中被扫描识别也容易在代码评审中被拦截。建议 3.4 不要写空有格式的函数头注释并不是所有函数都需要函数头注释函数尽量通过函数名自注释按需写函数头注释函数原型无法表达的、却又希望读者知道的信息才需要加函数头注释辅助说明。函数头注释内容可选但不限于功能说明、返回值、性能约束、用法、内存约定、算法实现、可重入的要求等。好的例子——说明了函数语义与调用者必须知道的内存约定/* * 返回实际写入的字节数-1表示写入失败 * 注意内存 buf 由调用者负责释放 */ int WriteString(const char *buf, int len);坏的例子——空有格式没内容函数名信息冗余关键信息缺失/* * 函数名WriteString * 功能写入字符串 * 参数 * 返回值 */ int WriteString(const char *buf, int len);上述坏例的问题在于参数、返回值空有格式没内容函数名信息冗余关键的buf由谁释放没有说清楚。建议 3.5 不用的代码段直接删除不要注释掉被注释掉的代码无法被正常维护当企图恢复使用这段代码时极有可能引入易被忽略的缺陷。正确的做法是不需要的代码直接删除掉若再需要时考虑移植或重写这段代码。工具链支撑clang-format 与 pre-commit 如何保障风格落地风格规范不只是纸面文档仓库提供了配套工具保证落地.clang-format配置对照仓库根目录 .clang-format 基于 Google 风格将上述大部分格式规则固化为机器可执行的配置关键项与规范的对应关系如下规范条目.clang-format配置项配置值建议 2.1 行宽 120ColumnLimit120规则 2.2 缩进 2 空格IndentWidth/TabWidth/UseTab2/2/Never规则 2.2 命名空间不缩进NamespaceIndentationNone规则 2.3 指针引用靠右PointerAlignmentRight规则 2.6 续行对齐操作数AlignOperandstrue规则 2.7 附着式大括号BreakBeforeBracesAttach规则 2.9 最多保留 1 个空行MaxEmptyLinesToKeep1同时该配置也保留了与规范存在张力的选项AllowShortIfStatementsOnASingleLine: true与AllowShortLoopsOnASingleLine: true允许单行 if/循环形式因此规则 2.4、2.5 的「必须加花括号」无法由 clang-format 自动保证需要依赖代码检视或 clang-tidyreadability-braces-around-statements补充。pre-commit 中的格式化与检查docs/zh/contributions/precommit_guide.md 说明了 pre-commit 的完整用法安装 pre-commit 后每次git commit前会自动执行代码格式化基于 clang-format 镜像、拼写检查codespell/typos与 OAT 合规扫描。格式化失败时会提示修改而真正的合规性问题二进制文件、许可证头缺失/错误会阻止提交。本地也可以手动运行检查# 安装 pre-commit 并安装 git hooks pip install pre-commit pre-commit install # 手动运行 OAT 合规检查 pre-commit run oat-check实战自查清单结合本文全部规则提交 C 代码前可对照以下清单快速自查命名文件名为小写下划线.h/.cpp统一后缀函数大驼峰且动词/动宾类型类/结构体/联合体/别名/枚举大驼峰普通变量 snake_case全局变量加g_类成员加_后缀宏与枚举值全大写下划线编译期常量k前缀大驼峰运行期 const 按普通变量。格式行宽 ≤ 1202 空格缩进且不用 Tab/*跟随变量名if/for/while 一律加大括号表达式换行运算符在行末且续行对齐操作数附着式大括号空函数体可同行一行一个变量定义连续空行最多 1 个代码块首尾不加空行。注释文件头带版权声明且年份正确右置注释用//且与代码间有空格禁止 TODO/TBD/FIXME函数头注释按需、有实质内容说明语义与内存约定等不用的代码直接删除而非注释掉。工具提交前运行 clang-format 对齐 .clang-format依赖 pre-commit 完成格式化、拼写与 OAT 合规检查避免二进制文件与许可证头问题阻塞提交。hixl 仓库中 src/hixl/cs/endpoint.cc、src/hixl/common/hixl_log.h、src/hixl/common/hixl_inner_types.h 等文件是上述规范的完整落地样例可以作为新代码的风格参考范本。【免费下载链接】hixlHIXLHuawei Xfer Library是一个灵活、高效的昇腾单边通信库面向集群场景提供简单、可靠、高效的点对点数据传输能力。项目地址: https://gitcode.com/cann/hixl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价