EMS 知识库
首页 / knowledge/代码解析/common/usmart

usmart_str.h

源文件路径: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_strcopycommon/usmart/usmart_str.c:52自实现字符串拷贝(str1 源、str2 目的)
usmart_strlencommon/usmart/usmart_str.c:70自实现字符串长度,返回 u8
usmart_search_nextccommon/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)的容量约定

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. 依赖关系

7. 备注与风险点

  1. 头文件声明不完整(最主要问题):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 约定不符。
  2. 依赖关系倒置:作为「字符串工具头文件」,它不包含 <string.h>,也不声明任何与标准库对应的包装,却把整个平台头(gd32f4xx.h + chip.h)拉进来。任何只需要 usmart_strcmp 的模块都会被迫引入寄存器定义。
  3. usmart_get_aparm 的 ptype 语义靠注释缺失传递:0 / 1 / 0xFF 三个取值在本文件中没有任何宏或注释说明(usmart_str.h:25 的注释只写「从 str 中得到一个函数参数」),取值定义实际藏在 usmart_str.c:355-359 与 usmart.c:428-451 的 switch 里,属跨文件魔法数字。
  4. usmart_strcmp 的返回值与标准库相反且无注释警示:usmart_str.h:20 的注释只写「对比两个字符串是否相等」,未说明「相等返回 0、不等返回 1」。若有人误按 strcmp 语义写 if (usmart_strcmp(a,b) > 0),逻辑会完全反转。
  5. 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。
  6. 无 extern "C" 保护:纯 C 工程,暂无影响;若将来把 USMART 编入 C++ 调试工具,符号会被 name mangling。
  7. 其余:暂无。