版本:v1.0 | 日期:2026-07-03
本规范规定 xt-sdk 源码的编码风格。所有新增/修改代码必须遵循本规范。
配套阅读:代码注释指南、文档编写指南。
一、文件头格式
1.1 通用文件头
所有 .h / .c 文件使用统一格式(参照 examples/misc/xt_template/ ):
/**
* @file xt_vfs.h
* @author your name (you@domain.com)
* @brief xt 虚拟文件系统——支持多后端挂载、两级锁、静态/动态内存切换
* @version 0.1
* @date 2026-06-16
*
* SPDX-FileCopyrightText: 2026 深圳市天工聚创科技有限公司
* SPDX-License-Identifier: Apache-2.0
*
*/
规则 :
- 使用 /** ... */ 多行注释块
- 字段顺序固定: @file → @author → @brief → @version → @date
- SPDX 上下各空一行
- 版权归属统一为 深圳市天工聚创科技有限公司
- 许可证统一为 Apache-2.0
1.2 测试文件头
测试文件增加 @details 描述覆盖范围:
/**
* @file xt_main.c
* @author your name (you@domain.com)
* @brief xt_vfs 单元测试套件
* @details 覆盖 init/deinit、mount/unmount、open/close 等 N 项测试
* @version 0.1
* @date 2026-06-16
*
* SPDX-FileCopyrightText: 2026 深圳市天工聚创科技有限公司
* SPDX-License-Identifier: Apache-2.0
*
*/
二、头文件保护
使用 #ifndef / #define / #endif 三元组,禁止 #pragma once。
#ifndef __XXX_H__
#define __XXX_H__
#endif
规则 :
- 宏命名: __<文件名大写>_H__
- 不带 xt_ 前缀(xt_ 是代码自身的命名空间,不是头文件保护的一部分)
- 尾部 #endif 必须加注释 /* __XXX_H__ */
三、Section 分隔符
3.1 格式
Section 分隔符是固定格式—— /* + 空格 + 若干 = + 空格 + [Name] + 空格 + 若干 = + */ ,**调整等号数量使行长度恰好为 80 列** (不含换行符)。
参照模板 examples/misc/xt_template/xt_template.h 和 examples/misc/xt_template/xt_template.c。
头文件 Section :
/* ==================== [Includes] ========================================== */
/* ==================== [Defines] =========================================== */
/* ==================== [Typedefs] ========================================== */
/* ==================== [Global Prototypes] ================================= */
/* ==================== [Macros] ============================================ */
源文件 Section :
/* ==================== [Includes] ========================================== */
/* ==================== [Defines] =========================================== */
/* ==================== [Typedefs] ========================================== */
/* ==================== [Static Prototypes] ================================= */
/* ==================== [Static Variables] ================================== */
/* ==================== [Macros] ============================================ */
/* ==================== [Global Functions] ================================== */
/* ==================== [Static Functions] ================================== */
规则 :
- Section 分隔符是固定格式, 禁止增删改
- 如需新增子分隔,用 /* --- xxx --- */ 或 doxygen @name, 不要用等号分隔符
- 保留空 Section(没有内容的 Section 也要有分隔符)
- 每个 Section 只能出现一次
3.2 Section 顺序
头文件 (5 个 Section):
[Includes] → [Defines] → [Typedefs] → [Global Prototypes] → [Macros]
源文件 (8 个 Section):
[Includes] → [Defines] → [Typedefs] → [Static Prototypes] → [Static Variables] → [Macros] → [Global Functions] → [Static Functions]
函数声明/定义顺序 :源文件 [Global Functions] 中函数的定义顺序必须和头文件 [Global Prototypes] 中函数的声明顺序严格一致。
四、缩进与空格
4.1 基本缩进
- **使用 4 个空格**,禁止使用 Tab
- 续行缩进对齐到上一行的合适位置
4.2 对齐
宏值、struct 成员等使用空格对齐以提高可读性:
#define XT_VFS_O_RDONLY 0x01
#define XT_VFS_O_WRONLY 0x02
#define XT_VFS_O_RDWR 0x04
int32_t xt_vfs_fd_t
文件描述符类型,内部编码 generation+index,由 VFS Core 生成,用户不应自行构造
int32_t xt_vfs_err_t
错误码类型,详细错误码见 XT_VFS_ERR_* 系列宏
uint32_t xt_vfs_size_t
文件大小类型(无符号)
4.3 条件编译缩进
条件编译块内的 #define 使用 # define(# + 空格 + define)缩进(对齐到 4 列的倍数):
#if !defined(XT_TIMER2_CRIT_STAT)
# define XT_TIMER2_CRIT_STAT() XT_CRIT_STAT()
#endif
五、大括号与控制流
5.1 函数
函数体的左大括号 独占一行 :
{
}
xt_vfs_err_t xt_vfs_init(const xt_vfs_config_t *config)
初始化 VFS 实例
struct xt_vfs_config xt_vfs_config_t
VFS 初始化配置
5.2 控制流
if / for / while 的左大括号与条件在同一行, else 采用 } else { 风格:
if (config == NULL) {
} else {
}
5.3 单行语句
单行语句也必须加大括号 :
5.4 逻辑条件
所有逻辑子条件必须加括号,多条件换行时运算符在行首:
if ((
a > 0) && (
b < 10)) {
}
if ((t->node.next != NULL)
&& (t->node.next != &t->node)
}
if (
a > 0 &&
b < 10) { ... }
if ((t->node.next != NULL) &&
(t->node.next != &t->node)) { ... }
static void xt_list_remove(struct xt_list_node *n)
remove node from list.
#define XT_TIMER2_FREE_MAGIC
内存池空闲槽位魔数标记
5.5 switch
case 与 switch 关键字对齐,每个 case 块必须用大括号包围,break 紧跟闭合大括号:
switch (err) {
case A: {
} break;
case B: {
} break;
default: {
} break;
}
六、命名约定
6.1 公共 API
函数命名约定 :
6.2 内部变量
| 类型 | 前缀 | 作用域 | 说明 |
| 静态变量(文件内) | s_ | 当前编译单元 | 主要形式 |
| 全局变量(跨文件) | g_ | 跨文件 | 一般不用 |
struct xt_timer2 xt_timer2_t
定时器句柄(前向声明)
struct xt_vfs xt_vfs_t
VFS 实例(前向声明)
6.3 局部变量
全小写蛇形命名,不使用前缀:
int path_len;
xt_vfs_handle_t *backend_h;
6.4 struct 成员
全小写蛇形命名,不使用前缀:
};
uint32_t xt_vfs_mode_t
文件模式类型(权限 + 类型)
七、注释
7.1 注释风格选择
| 场景 | 风格 | 说明 |
| 文档注释(函数/类型/宏) | /** ... */ | doxygen 多行注释 |
| 文档注释(单行) | /** @brief ... */ | 简短说明 |
| 行内成员注释 | /*!< ... */ | 推荐, /**< 也可 |
| 内部注释 | /* ... */ | 非文档注释 |
| TODO | // TODO: ... | 仅此场景允许 // |
// 通常不推荐用于普通注释,但不做严格限制。
7.2 函数注释
头文件注释写 接口契约 (干什么、参数要求、返回值、注意事项),源文件注释写 实现细节 (怎么干的、为什么这样干),两者不重复。
头文件 :
/**
* @brief 启动/重启定时器,挂入工作链表
*
* 临界区内计算绝对超时,若已在工作链表上则先摘后挂。
*
* @param t 定时器句柄,不可为 NULL
* @param tick_timeout 超时 tick 数(相对)
*
* @return XT_EOK 成功
* @return XT_EINVAL 参数无效或 timeout 超限
*
* @note 回调中调 start(self) 合法——先摘后挂重新调度。
*/
xt_err_t xt_timer2_start(xt_timer2_t *t, xt_tick2_t tick_timeout);
源文件 :
/**
* @brief 启动/重启定时器
*
* 临界区内先摘后挂:若 node 已在链表上则 xt_list_remove 摘下旧位置,
* 再计算绝对超时并 xt_list_insert_after 挂入 s_working_head。
* 先摘后挂保证对已运行的定时器调用 start 等价于 restart。
*
* timeout 超限也 assert(和 cb_func==NULL 同为编程错误),
* 因为超限值会破坏 remain() 的有符号差值回绕安全性。
*/
xt_err_t xt_timer2_start(xt_timer2_t *t, xt_tick2_t tick_timeout)
{
/* ... */
}
八、条件编译
8.1 可配置宏
头文件保护除外,其余地方一律使用 #if defined() / #if !defined() ,禁止 #ifdef / #ifndef。
#if !defined(XT_VFS_USE_HEAP)
#define XT_VFS_USE_HEAP 1
#endif
#ifndef XT_VFS_USE_HEAP
#define XT_VFS_USE_HEAP 1
#endif
8.2 endif 注释
#endif 必须加注释追踪条件:
#if XT_VFS_ENABLE_DIR
#endif
8.3 平台检测
#if defined(XT_SDK_PLATFORM_WINDOWS)
#elif defined(XT_SDK_PLATFORM_LINUX)
#else
#endif
九、数据类型
9.1 typedef
类型名统一使用 _t 后缀,前向声明使用 typedef struct 模式:
struct xt_vfs_ops xt_vfs_ops_t
后端操作接口(前向声明)
9.2 struct
struct xt_vfs_stat xt_vfs_stat_t
文件状态信息
9.3 函数指针
void(* xt_timer2_cb_t)(xt_timer2_t *t, void *user_data)
定时器回调函数类型
9.4 前向声明
十、宏定义
10.1 配置宏默认值
可被 xmake 覆盖的配置宏使用 #if !defined() 提供默认值:
#if !defined(XT_VFS_ENABLE_THREAD_SAFE)
#define XT_VFS_ENABLE_THREAD_SAFE 1
#endif
10.2 函数式宏
需要时使用 do { ... } while (0) 包裹多语句宏:
#define XT_VFS_LOCK(mp) \
do { \
if (XT_VFS_ENABLE_THREAD_SAFE) { \
osMutexAcquire((mp)->lock, osWaitForever); \
} \
} while (0)
10.3 错误码
十一、函数规范
11.1 声明/定义风格
- 返回类型和函数名在同一行
- 多参数换行时,对齐到第一个参数的开头位置
- 一行一个变量声明
void *user_data);
xt_err_t xt_timer2_setup(xt_timer2_t *t, xt_timer2_cb_t timer_cb, void *user_data)
配置定时器回调函数和用户数据(不启动)
11.2 参数声明
- const 修饰指针指向对象时放在类型后面: const xt_vfs_ops_t *ops
- const 修饰参数本身时放在类型前面: const char *path
11.3 临界区使用
锁的获取和释放必须在同一函数内配对,提前返回前必须先解锁:
{
xt_vfs_handle_t *h;
if (buf == NULL) {
}
if (h == NULL) {
}
}
#define XT_VFS_TYPE_REG
普通文件
#define XT_VFS_ERR_INVAL
无效参数
xt_vfs_ssize_t xt_vfs_read(xt_vfs_fd_t fd, void *buf, xt_vfs_size_t size)
读取文件
#define XT_VFS_UNLOCK(vfs)
释放锁
#define XT_VFS_LOCK(vfs)
获取锁(阻塞等待)
11.4 assert 模式
Windows 上 xt_assert_failed 只打印不退出进程, assert 后必须显式返回或退出 :
if (t == NULL) {
}
if (timer_cb == NULL) {
return NULL;
}
t->cb_func = cb;
#define XT_ASSERT_MSG(expr, errcode)
11.5 extern "C"
头文件中 extern "C" 紧接 [Includes] Section 之后:
#include "xxx.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif
十二、栈审计
>64 字节的局部数组 必须 改为 static 或动态分配。
- 通常建议动态分配 (灵活性好、无线程安全问题)
- 若使用 static 数组,接口必须用锁保护(否则多线程不安全)
char *fullpath = malloc(path_len);
free(fullpath);
snprintf(s_fullpath, sizeof(s_fullpath), "%s/%s", nc->base_path, path);
char fullpath[256];
#define XT_VFS_PATH_MAX
最大路径长度(含结尾 '\0')
十三、include 顺序
13.1 头文件
#include <stdint.h>
xt_vfs 可移植层——锁宏、内存宏、线程上下文
13.2 源文件
#include <string.h>
#include <stdio.h>
xt 虚拟文件系统——支持多后端挂载、两级锁、静态/动态内存切换
规则 :
- 标准库头文件( <...> )在前,项目头文件( "..." )在后
- 项目头文件中,本组件头文件放首位
- 不同类别之间空行分隔
十四、测试代码规范
测试代码的完整规范(命名、断言、G/W/T 结构、覆盖场景、多配置测试等)详见 测试规范。本章仅保留核心要点。
14.1 关键差异
测试文件与源码文件的**不同之处**:
- 测试文件**不用 Section 分隔符**,改用 doxygen @name + @{}/@} 分组
- setUp / tearDown 不加 static (Unity 框架要求)
- 入口函数固定为 int xt_main(void)
14.2 最小模板
/**
* @file xt_main.c
* @author your name (you@domain.com)
* @brief <模块名> 单元测试套件
* @details 覆盖 <简述>。基于 Unity 测试框架运行。
* @version 0.1
* @date YYYY-MM-DD
*
* SPDX-FileCopyrightText: YYYY 深圳市天工聚创科技有限公司
* SPDX-License-Identifier: Apache-2.0
*
*/
#include "unity.h"
#include "xtiny.h"
/** @name setUp / tearDown */
/** @{ */
void setUp(void) { }
void tearDown(void) { }
/** @} */
/** @name 1. 基本功能 (N 项测试) */
/** @{ */
static void test_xxx(void) { /* ... */ }
/** @} */
int xt_main(void)
{
UNITY_BEGIN();
RUN_TEST(test_xxx);
return UNITY_END();
}
14.3 xmake.lua
local TARGET_NAME = "xt_main"
target(TARGET_NAME)
set_kind("static")
add_deps("xt_core")
add_deps("xt_unity")
add_files("xt_main.c")
target_end()
完整规范(断言选择、G/W/T 结构、覆盖场景分类、多配置自动化测试等)见 测试规范。
十五、doxygen 分组
源代码中的 doxygen 分组规范详见 代码注释指南(v0.1),核心要点:
- 组件头文件用 @defgroup 创建模块分组,用 @name 划分子分区
- 组闭合用单行 /** @} */ /* 组名 */
- 开发者接口子组命名为 xt_xxx__dev(双下划线后缀)
- 无总头文件的组件组定义在 .dox 文件中
参考文件