usmart_str.h
u8 / u32)的容量约定4.3 与 uCOS-II 的配合5. 对外接口6. 依赖关系7. 备注与风险点源文件路径:
common/usmart/usmart_str.h所属模块:common / usmart(串口调试交互组件) 代码行数:29
1. 文件职责
本文件是 USMART 文本解析层的对外头文件,声明了 8 个字符串与参数解析函数的原型,供 common/usmart/usmart.c 在识别串口命令、解析函数名与实参时调用。它处在调试基础设施的接口层:本身没有任何可执行代码、不定义变量、不涉及任务调度,只提供函数契约,并把平台类型头(gd32f4xx.h、chip.h)向下传递给 usmart.h(usmart.h:15 直接 #include "usmart_str.h"),是整条依赖链上唯一声明 u8/u16/u32 来源的地方。它的一个显著特点是声明不完整:usmart_str.c 里定义的 11 个函数中有 3 个(usmart_strcopy、usmart_strlen、usmart_search_nextc)没有在这里声明(详见第 7 节)。本文件不直接受 DEBUG_SUMART 控制(它没有 #if 守卫),但它的实现体 usmart_str.c 整体在 #if DEBUG_SUMART 内,DEBUG_SUMART 当前为 0(midware/debug/shell_usmart.h:13)。
2. 关键数据结构与宏
| 名称 | 类型(结构体/枚举/宏/联合体) | 说明 |
|---|---|---|
__USMART_STR_H | 宏(include guard) | usmart_str.h:9-10,防重包含开关 |
本文件没有定义任何其他宏、结构体、枚举或联合体,也没有 extern 变量声明。它用到的全部类型(u8、u16、u32)都由 usmart_str.h:14-15 的两个 #include 提供。
3. 函数清单
本文件是头文件,不含函数定义,仅含 8 个函数原型声明:
| 函数名 | 作用域(static/全局) | 说明(一句话) |
|---|---|---|
usmart_get_parmpos | 全局(声明,usmart_str.h:19) | 用 usmart_dev.plentbl[] 前缀和算出第 num 个参数在参数缓冲中的起始偏移 |
usmart_strcmp | 全局(声明,usmart_str.h:20) | 自实现字符串比较,相等返回 0、不等返回 1(语义与标准 strcmp 相反) |
usmart_pow | 全局(声明,usmart_str.h:21) | 整数幂 m^n,循环累乘实现,返回 u32 |
usmart_str2num | 全局(声明,usmart_str.h:22) | 文本转数字,自动识别十进制与 0X 前缀十六进制,返回 0 成功 / 1~4 错误码 |
usmart_get_cmdname | 全局(声明,usmart_str.h:23) | 从字符串首部取命令词并回传长度,超过 maxlen 返回 1 |
usmart_get_fname | 全局(声明,usmart_str.h:24) | 从函数声明串解析裸函数名、形参个数与「返回类型是否为 void」 |
usmart_get_aparm | 全局(声明,usmart_str.h:25) | 从实参串解析出单个参数并回传其类型(数字 / 字符串 / 非法) |
usmart_get_fparam | 全局(声明,usmart_str.h:26) | 解析整行实参并按 USMART 打包格式写入 usmart_dev.parm[] / plentbl[] / parmtype |
在 usmart_str.c 中定义、但本文件未声明的函数(头文件与实现不同步):
| 函数名 | 实现位置 | 说明 |
|---|---|---|
usmart_strcopy | common/usmart/usmart_str.c:52 | 自实现字符串拷贝(str1 源、str2 目的) |
usmart_strlen | common/usmart/usmart_str.c:70 | 自实现字符串长度,返回 u8 |
usmart_search_nextc | common/usmart/usmart_str.c:184 | 跳过当前字符及其后的空格,返回下一个非空格字符 |
4. 核心逻辑解析
本文件无过程代码。以下说明其声明的接口在调用链上的位置与相互约束,这些约束是理解 usmart_str.c 与 usmart.c 协作的前提。
4.1 8 个原型的调用顺序约束
这 8 个函数构成一条有严格先后关系的流水线,不能任意调换顺序:
usmart_get_cmdname(str, cmdname, &nlen, MAX_FNAME_LEN) ← 先判是否为系统命令
│(若不是系统命令)
▼
usmart_get_fname(str, fname, &pnum, &rval) ← 解析函数名与形参个数,rval 指明返回值
│(与 usmart_dev.funs[i].name 逐个 usmart_strcmp 比对,命中后)
▼
usmart_get_fparam(str, &n) ← 解析实参
│ 内部循环 usmart_get_aparm(str, tstr, &type)
│ 数字分支调用 usmart_str2num(tstr, &res)
│ 字符串分支调用 usmart_strlen / usmart_strcopy
└── 写入 usmart_dev.plentbl[] / parm[] / parmtype
│
▼
usmart_get_parmpos(i) ← 后续取值时用前缀和取偏移
(被 usmart.c:334/336 与 usmart_str.c:434/443 使用)
关键约束:usmart_get_parmpos 的返回值只在 usmart_get_fparam 填好 plentbl[] 之后才有意义。usmart.c:334-339(usmart_exe 打印字符串参数)与 usmart.c:336(取参数指针)都依赖这一点;若 plentbl[] 是陈旧的,取到的参数地址就会落到错误偏移上。
usmart_strcmp 的返回值语义与标准库相反(相同返 0、不同返 1),usmart.c:151, 231, 294, 310 四处都按这个语义使用(if(usmart_strcmp(a,b)==0) 表示相等)。这是使用本头文件时最容易踩的坑。
4.2 返回类型(u8 / u32)的容量约定
- 8 个原型中有 6 个返回
u8。这让usmart_get_cmdname/usmart_get_fname/usmart_get_aparm/usmart_get_fparam的「长度」或「计数」类返回值天然被限制在 0~255;usmart_str2num/usmart_strcmp的返回是状态码,取值 0~4,容量够用。 usmart_pow返回u32,配合usmart_str2num内部的u32 res(usmart_str.c:104)共同支撑 8 位十六进制的解析上限。usmart_get_aparm的第三个参数u8 *ptype会被写入0(数字)、1(字符串)、0xFF(非法)三种取值,因此必须按u8而不是按「布尔」理解。
4.3 与 uCOS-II 的配合
无。本文件不声明任何 uCOS-II 类型或对象,也不参与信号量、消息邮箱、任务创建。它声明的函数全部是纯计算函数,唯一的共享状态是对 usmart_dev(由 usmart.h:66 声明、midware/debug/shell_usmart.c:32 定义)的读写,互斥责任落在调用方 usmart.c 上(而 usmart.c 目前并没有做互斥)。
5. 对外接口
导出(供外部调用)
| 符号 | 类型 | 使用者 |
|---|---|---|
__USMART_STR_H | 宏 | 头文件自身防重包含;无外部引用 |
usmart_get_parmpos | 函数原型 | common/usmart/usmart.c:334, 336;common/usmart/usmart_str.c:434, 443 |
usmart_strcmp | 函数原型 | common/usmart/usmart.c:151, 231, 294, 310;common/usmart/usmart_str.c:231, 310 |
usmart_pow | 函数原型 | common/usmart/usmart_str.c:148 |
usmart_str2num | 函数原型 | common/usmart/usmart.c:198, 226, 253;common/usmart/usmart_str.c:431 |
usmart_get_cmdname | 函数原型 | common/usmart/usmart.c:145 |
usmart_get_fname | 函数原型 | common/usmart/usmart.c:187, 287, 291, 327 |
usmart_get_aparm | 函数原型 | common/usmart/usmart.c:195, 223, 250;common/usmart/usmart_str.c:424 |
usmart_get_fparam | 函数原型 | common/usmart/usmart.c:304 |
类型 u8 / u16 / u32 | 透传(来自 gd32f4xx.h / chip.h) | usmart.h 及其上游所有使用者 |
本文件不导出任何全局变量。
被本文件调用(外部依赖)
| 符号 | 来源 |
|---|---|
| GD32 标准外设库类型与寄存器定义 | gd32f4xx.h(usmart_str.h:14) |
Alpha 平台通用定义(u8 / u16 / u32 等) | chip.h(usmart_str.h:15) |
6. 依赖关系
- 依赖:
gd32f4xx.h、chip.h。本文件不依赖工程内任何其他模块。 - 被依赖:
common/usmart/usmart.h(usmart.h:15直接包含本文件,借此向上游提供类型);common/usmart/usmart.c(使用全部 8 个原型);common/usmart/usmart_str.c(自身实现者,同时使用usmart_strcmp/usmart_pow/usmart_str2num/usmart_get_aparm/usmart_get_parmpos/usmart_get_fparam);- 经
usmart.h间接影响midware/debug/shell_usmart.c。
7. 备注与风险点
- 头文件声明不完整(最主要问题):
common/usmart/usmart_str.c一共定义了 11 个函数,本文件只声明了 8 个。缺失的是usmart_strcopy(usmart_str.c:52)、usmart_strlen(usmart_str.c:70)、usmart_search_nextc(usmart_str.c:184)。这三个函数都未加static,属「有实现无契约」的导出符号;严格 C99/C11 编译器在隐式声明时会报错或按int处理返回值,而usmart_strlen返回u8、usmart_strcopy无返回值,与隐式int约定不符。 - 依赖关系倒置:作为「字符串工具头文件」,它不包含
<string.h>,也不声明任何与标准库对应的包装,却把整个平台头(gd32f4xx.h+chip.h)拉进来。任何只需要usmart_strcmp的模块都会被迫引入寄存器定义。 usmart_get_aparm的ptype语义靠注释缺失传递:0/1/0xFF三个取值在本文件中没有任何宏或注释说明(usmart_str.h:25的注释只写「从 str 中得到一个函数参数」),取值定义实际藏在usmart_str.c:355-359与usmart.c:428-451的switch里,属跨文件魔法数字。usmart_strcmp的返回值与标准库相反且无注释警示:usmart_str.h:20的注释只写「对比两个字符串是否相等」,未说明「相等返回 0、不等返回 1」。若有人误按strcmp语义写if (usmart_strcmp(a,b) > 0),逻辑会完全反转。usmart_get_cmdname的nlen是「长度」而非「状态」:原型为u8 usmart_get_cmdname(u8*str, u8*cmdname, u8 *nlen, u8 maxlen),nlen回传匹配到的命令词长度,返回值为错误码(0 成功 / 1 超长)。同一行两个u8分别是「长度」与「状态」,调用方极易混淆——usmart.c:145处的用法是把两者分别接给i与res。- 无
extern "C"保护:纯 C 工程,暂无影响;若将来把 USMART 编入 C++ 调试工具,符号会被 name mangling。 - 其余:暂无。