xt-sdk 文档 v1.0.3
xt-sdk 嵌入式 SDK API 参考
载入中...
搜索中...
未找到
编码规范

版本: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 /* __XXX_H__ */

规则 :

  • 宏命名: __<文件名大写>_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
typedef int32_t xt_vfs_err_t;
typedef int32_t xt_vfs_fd_t;
typedef uint32_t xt_vfs_size_t;
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) {
return XT_EINVAL;
} else {
/* ... */
}
#define XT_EINVAL

5.3 单行语句

单行语句也必须加大括号 :

// 正确
if (t == NULL) {
return XT_EINVAL;
}
// 错误
if (t == NULL) return XT_EINVAL;

5.4 逻辑条件

所有逻辑子条件必须加括号,多条件换行时运算符在行首:

// 正确
if ((a > 0) && (b < 10)) {
/* ... */
}
if ((t->node.next != NULL)
&& (t->node.next != &t->node)
&& (t->node.next != (struct xt_list_node *)XT_TIMER2_FREE_MAGIC)) {
xt_list_remove(&t->node);
}
// 错误
if (a > 0 && b < 10) { ... }
if ((t->node.next != NULL) &&
(t->node.next != &t->node)) { ... }
const char * a(void)
const char * b(void)
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: {
/* xxx */
} break;
case B: {
/* xxx */
} break;
default: {
/* xxx */
} break;
}

六、命名约定

6.1 公共 API

类型 格式 示例
函数 xt_<组件>_<动作>_<对象> ,全小写蛇形命名 xt_vfs_open, xt_timer2_start
类型 xt_<组件>_<名称>_t ,全小写蛇形命名 xt_vfs_fd_t, xt_timer2_cb_t
宏 XT_<组件>_<名称> ,全大写蛇形命名 XT_VFS_O_RDONLY, XT_TIMER2_TIMEOUT_MAX

函数命名约定 :

操作 命名 示例
创建/分配 <prefix>_new xt_timer2_new
初始化 <prefix>_init xt_vfs_init
启动 <prefix>_start xt_timer2_start
停止 <prefix>_stop xt_timer2_stop
销毁 <prefix>_deinit xt_vfs_deinit
查询状态 <prefix>_is_<状态> xt_vfs_is_active
获取/设置 <prefix>_get_<属性>, <prefix>_set_<属性> —

6.2 内部变量

类型 前缀 作用域 说明
静态变量(文件内) s_ 当前编译单元 主要形式
全局变量(跨文件) g_ 跨文件 一般不用
static xt_timer2_t *s_working_head; // 文件内静态变量
xt_vfs_t g_vfs; // 全局变量(一般不用)
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 成员

全小写蛇形命名,不使用前缀:

struct xt_vfs_stat {
};
uint32_t xt_vfs_mode_t
文件模式类型(权限 + 类型)
文件状态信息
xt_vfs_mode_t st_mode
xt_vfs_size_t st_size

七、注释

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 /* XT_VFS_ENABLE_DIR */

8.3 平台检测

#if defined(XT_SDK_PLATFORM_WINDOWS)
/* Windows 实现 */
#elif defined(XT_SDK_PLATFORM_LINUX)
/* Linux 实现 */
#else
/* 默认(嵌入式 lwip 等) */
#endif

九、数据类型

9.1 typedef

类型名统一使用 _t 后缀,前向声明使用 typedef struct 模式:

typedef struct xt_vfs xt_vfs_t;
typedef struct xt_vfs_ops xt_vfs_ops_t;
typedef int32_t xt_vfs_err_t;
typedef uint32_t xt_vfs_size_t;
struct xt_vfs_ops xt_vfs_ops_t
后端操作接口(前向声明)

9.2 struct

// 有 typedef 的 struct
typedef struct xt_vfs_stat {
struct xt_vfs_stat xt_vfs_stat_t
文件状态信息

9.3 函数指针

typedef void (*xt_timer2_cb_t)(xt_timer2_t *t, void *user_data);
void(* xt_timer2_cb_t)(xt_timer2_t *t, void *user_data)
定时器回调函数类型

9.4 前向声明

typedef struct xt_vfs_ops xt_vfs_ops_t;

十、宏定义

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 错误码

级别 格式 示例
全局错误码 XT_E<名称> XT_EOK, XT_EINVAL, XT_ENOMEM
组件错误码 XT_<组件>_ERR_<名称> XT_VFS_ERR_OK, XT_VFS_ERR_EOF

十一、函数规范

11.1 声明/定义风格

  • 返回类型和函数名在同一行
  • 多参数换行时,对齐到第一个参数的开头位置
  • 一行一个变量声明
// 短参数列表——一行
// 长参数列表——对齐换行
xt_timer2_cb_t timer_cb,
void *user_data);
// 一行一个变量
int a;
int b;
int32_t xt_err_t
错误码类型
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) {
return _vfs_set_errno(XT_VFS_ERR_INVAL);
}
XT_VFS_LOCK((&g_vfs));
h = _validate_fd_locked(fd, XT_VFS_TYPE_REG);
if (h == NULL) {
XT_VFS_UNLOCK((&g_vfs)); // 提前返回前解锁
return _vfs_set_errno(XT_VFS_ERR_INVAL);
}
/* ... */
XT_VFS_UNLOCK((&g_vfs));
/* ... */
}
#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 后必须显式返回或退出 :

// 正确:assert 后显式返回
if (t == NULL) {
return XT_EINVAL;
}
// 正确:指针返回
if (timer_cb == NULL) {
return NULL;
}
// 错误:assert 后继续执行,可能访问 NULL 指针
t->cb_func = cb; // t==NULL 时崩溃
#define XT_ASSERT_MSG(expr, errcode)

11.5 extern "C"

头文件中 extern "C" 紧接 [Includes] Section 之后:

/* ==================== [Includes] ========================================== */
#include "xxx.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ==================== [Defines] =========================================== */
/* ... 其余 Section ... */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __XXX_H__ */

十二、栈审计

>64 字节的局部数组 必须 改为 static 或动态分配。

  • 通常建议动态分配 (灵活性好、无线程安全问题)
  • 若使用 static 数组,接口必须用锁保护(否则多线程不安全)
// 推荐:动态分配
char *fullpath = malloc(path_len);
/* ... */
free(fullpath);
// 可用:static 数组(需锁保护)
static char s_fullpath[XT_VFS_PATH_MAX * 2]; // 由后端锁保护
snprintf(s_fullpath, sizeof(s_fullpath), "%s/%s", nc->base_path, path);
// 错误:大局部数组存在栈溢出风险
char fullpath[256];
#define XT_VFS_PATH_MAX
最大路径长度(含结尾 '\0')

十三、include 顺序

13.1 头文件

/* ==================== [Includes] ========================================== */
#include <stdint.h> // 标准库头文件
#include "xt_vfs_port.h" // 项目头文件
xt_vfs 可移植层——锁宏、内存宏、线程上下文

13.2 源文件

/* ==================== [Includes] ========================================== */
#include <string.h> // 标准库头文件
#include <stdio.h>
#include "xtiny.h" // 项目头文件
#include "xt_vfs.h" // 本组件头文件(放在项目头文件首位)
xt 虚拟文件系统——支持多后端挂载、两级锁、静态/动态内存切换
XTINY 总头文件

规则 :

  • 标准库头文件( <...> )在前,项目头文件( "..." )在后
  • 项目头文件中,本组件头文件放首位
  • 不同类别之间空行分隔

十四、测试代码规范

测试代码的完整规范(命名、断言、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 文件中

参考文件