目录
一、长度查询类
二、比较类
三、复制/填充类
四、连接/拼接类
五、查找/搜索类
六、转换类
七、实用工具类
八、STM32 常用技巧与陷阱
1. 避免的函数
2. 安全替代方案
3. 内存对齐与 Flash 字符串
4. RTOS 环境下的重入问题
5. Newlib 配置优化
九、quick reference 速查表
在 STM32 开发中,字符串操作主要依赖标准 C 库<string.h>和<stdio.h>中的函数。由于资源受限,通常需注意内存消耗、重入性和缓冲区安全。
一、长度查询类
| 函数 | 原型 | 用途 | STM32 注意点 |
|---|---|---|---|
strlen | size_t strlen(const char *s); | 返回字符串长度(不含\0) | 空指针、越界风险 |
strnlen | size_t strnlen(const char *s, size_t maxlen); | 限制最大长度的strlen | STM32 推荐,防无限读取 |
// 示例:安全获取长度 size_t len = strnlen(buf, sizeof(buf) - 1);二、比较类
| 函数 | 原型 | 用途 | STM32 注意点 |
|---|---|---|---|
strcmp | int strcmp(const char *s1, const char *s2); | 逐字符比较(区分大小写) | 返回 0 表示相等 |
strncmp | int strncmp(const char *s1, const char *s2, size_t n); | 比较前 n 个字符 | STM32 推荐,防溢出 |
strcasecmp | int strcasecmp(const char *s1, const char *s2); | 不区分大小写比较 | 部分库支持(Newlib 有) |
// 示例:安全比较命令 if (strncmp(cmd, "AT+", 3) == 0) { /* ... */ }三、复制/填充类
| 函数 | 原型 | 用途 | STM32 注意点 |
|---|---|---|---|
strcpy | char *strcpy(char *dest, const char *src); | 复制字符串(含\0) | ❌ 危险!无边界检查 |
strncpy | char *strncpy(char *dest, const char *src, size_t n); | 复制最多 n 个字符 | 必用,但需手动补\0 |
memcpy | void *memcpy(void *dest, const void *src, size_t n); | 内存块复制(不关心\0) | STM32 高频使用,效率高 |
memset | void *memset(void *s, int c, size_t n); | 内存块设置 | 常用于清空缓冲区 |
// 推荐写法:strncpy + 强制终止 char buf[32]; strncpy(buf, src, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; // 确保终止四、连接/拼接类
| 函数 | 原型 | 用途 | STM32 注意点 |
|---|---|---|---|
strcat | char *strcat(char *dest, const char *src); | 拼接字符串 | ❌ 极易溢出 |
strncat | char *strncat(char *dest, const char *src, size_t n); | 最多拼接 n 个字符 | 需先确保 dest 有剩余空间 |
snprintf | int snprintf(char *s, size_t n, const char *fmt, ...); | 格式化拼接(推荐) | C99 标准,STM32 常用 |
// Roson 推荐:snprintf 组合字符串(安全且灵活) char msg[64]; int len = snprintf(msg, sizeof(msg), "TEMP:%d,HUM:%d", temp, hum);五、查找/搜索类
| 函数 | 原型 | 用途 | STM32 注意点 |
|---|---|---|---|
strchr | char *strchr(const char *s, int c); | 查找字符首次出现 | 返回 NULL 表示未找到 |
strrchr | char *strrchr(const char *s, int c); | 查找字符最后一次出现 | 常用于取文件扩展名 |
strstr | char *strstr(const char *haystack, const char *needle); | 查找子串 | 无则返回 NULL |
strpbrk | char *strpbrk(const char *s, const char *accept); | 查找第一个出现在accept集合的字符 | 常用于分隔符解析 |
// 示例:查找 AT 命令返回值中的 "\r\n" char *p = strstr(buf, "\r\n");六、转换类
| 函数 | 原型 | 用途 | STM32 注意点 |
|---|---|---|---|
atoi | int atoi(const char *nptr); | 字符串转 int | 无错误处理,不推荐 |
atol | long atol(const char *nptr); | 字符串转 long | 同上 |
strtol | long strtol(const char *nptr, char **endptr, int base); | 推荐,支持进制转换 | 可检测转换错误 |
sprintf | int sprintf(char *s, const char *fmt, ...); | 格式化输出到字符串 | ❌ 无边界检查,危险 |
snprintf | int snprintf(char *s, size_t n, ...); | 安全版 sprintf | STM32 必备 |
// 推荐:strtol 转换(带错误检查) char *end; long val = strtol(str, &end, 10); if (*end != '\0') { /* 转换不完整 */ }七、实用工具类
| 函数 | 原型 | 用途 | STM32 场景 |
|---|---|---|---|
strtok | char *strtok(char *str, const char *delim); | 按分隔符切分字符串 | 解析 AT 命令、JSON 字段 |
strspn | size_t strspn(const char *s, const char *accept); | 返回接受字符集的跨度 | 跳过前导空白/固定头 |
strcspn | size_t strcspn(const char *s, const char *reject); | 返回排斥字符集的跨度 | 同上 |
memchr | void *memchr(const void *s, int c, size_t n); | 内存中查找字符 | 适用于二进制+文本混合 |
// 示例:解析 CSV char *token = strtok(line, ","); while (token) { process(token); token = strtok(NULL, ","); }八、STM32 常用技巧与陷阱
1.避免的函数
// 危险!ST 标准库可能不检查边界 strcpy(dest, src); // ❌ 禁止 strcat(dest, src); // ❌ 禁止 sprintf(buf, "%s", str); // ❌ 禁止(溢出风险)2.安全替代方案
// 安全拷贝 strncpy(dest, src, sizeof(dest)-1); dest[sizeof(dest)-1] = '\0'; // 安全格式化(STM32 强烈推荐) snprintf(buf, sizeof(buf), "%.2f", voltage);3.内存对齐与 Flash 字符串
// STM32 中,字符串字面量通常在 Flash(.rodata) // 如需放入 RAM,使用 PROGMEM 等效方案(HAL 库无,需自定义) // 示例:RAM 中的 const 字符串 const char cmd_ok[] = "OK\r\n"; HAL_UART_Transmit(&huart1, (uint8_t*)cmd_ok, strlen(cmd_ok), 100);4.RTOS 环境下的重入问题
// 自由RTOS下:strtok 不是线程安全的! // 使用 strtok_r(GNU 扩展)或自行实现 char *strtok_r(char *str, const char *delim, char **saveptr);5.Newlib 配置优化
STM32 HAL 默认使用 Newlib 或 Newlib-nano,可在syscalls.c中实现轻量版_sbrk、_write后,字符串函数体积可控。
九、quick reference 速查表
// 最常用组合(STM32 推荐) strlen() → 长度(优先 strnlen) strncmp() → 安全比较 memcpy() → 块复制(最快) snprintf() → 格式化输出(代替 sprintf) strstr() → 子串搜索 strtok_r() → 线程安全切分 strtol() → 带错误检查的数值转换总结:STM32 下字符串处理的核心原则是:优先 strn族、摒弃 str无边界函数、强制用 snprintf、配合 RTOS 时注意重入性。**