代码中相关C语言知识点总结

1.strstr字符

strstr(command, "$cmd,get ant para") 的作用是:

在字符串 command 中查找是否包含子串 "$cmd,get ant para"

函数原型一般是:

复制代码

cs 复制代码
char *strstr(const char *str1, const char *str2);

含义:

str1:被查找的字符串,这里就是 command

str2:要查找的子串,这里是 "$cmd,get ant para

返回值:如果找到了,返回子串第一次出现的位置指针如果没找到,返回 NULL

2.sscanf

cs 复制代码
   /* 从命令中提取单个增益值 */
            char *comma1 = strstr(command, "rx");
            if (comma1 == NULL ||
                sscanf(comma1 + 2, ",%lf", &rx_gain_db) != 1 ||
                rx_gain_db < 0.0 || rx_gain_db > 30.0)
            {
                Cmd_Reply("$cmd,set convert gain,rx,ack error\r\n");
                return;
            }
  • strstr(command, "rx")command 里查找子串 "rx"
  • 如果找到了,返回指向 'r' 的指针;
  • 如果没找到,返回 NULL
cs 复制代码
    sscanf(comma1 + 2, ",%lf", &rx_gain_db) != 1 ||
  • comma1 + 2:跳过 "rx" 这两个字符,指向紧跟在 "rx" 后面的内容。

  • 格式化字符串 ",%lf" 的意思是:

    1. 先匹配一个逗号 ,
    2. 然后读取一个浮点数,存入 rx_gain_db 中。
  • sscanf 的返回值是"成功赋值的变量个数"。这里只有 %lf 一个变量,所以成功时必须返回 1

  • 如果 "rx" 后面不是 ,数字 这种格式,比如是 "rxabc""rx abc"sscanf 会失败,返回值不等于 1,进入错误处理。

3.大端序

cs 复制代码
void XW_On_SetBDC_Attenuation(uint16_t att_01db)
{
    /* 对应 $cmd,down convert 3 */
    uint16_t value = ((float)att_01db / 100.0f) * 10;
		actuallyDownGain = att_01db;
    downConvertGain[8] = (value >> 8) & 0xFF;
    downConvertGain[9] = value & 0xFF;
    downConvertGain[10] = (CRC16_Calculate(downConvertGain, 10) >> 8) & 0xFF;
    downConvertGain[11] = CRC16_Calculate(downConvertGain, 10) & 0xFF;

    UART3_TX_DMA_Send(downConvertGain, sizeof(downConvertGain));
}
cs 复制代码
downConvertGain[8] = (value >> 8) & 0xFF;
downConvertGain[9] = value & 0xFF;

这两句就是把 16 位的 value 拆成两个字节:

  • downConvertGain[8] 存的是 高 8 位
  • downConvertGain[9] 存的是 低 8 位
  • 这种写法叫 大端序(Big-Endian,高字节在前)。先发高字节再发低字节

4.strncmp

功能:比较字符串前 n 个字符

cs 复制代码
#include <string.h>

int strncmp(const char *s1, const char *s2, size_t n);
返回值 含义
0 s1s2 的前 n 个字符完全相同
< 0 s1 的前 n 个字符小于 s2(按无符号字节值比较)
> 0 s1 的前 n 个字符大于 s2
cs 复制代码
static const char prefix[] = "$cmd,set ephem;";
if (command == NULL ||
    strncmp(command, prefix, sizeof(prefix) - 1U) != 0) return 0;

p = command + sizeof(prefix) - 1U;

说明:

  1. prefix 是命令头:"$cmd,set ephem;"

    • 它的长度是 15 个字符;
    • sizeof(prefix) 是 16(包含结尾的 '\0');
    • sizeof(prefix) - 1U 就是 15,即不比较字符串结束符
  2. strncmp(command, prefix, 15) != 0

    • 判断 command 的开头 15 个字节是否正好等于 "$cmd,set ephem;"
    • 这就是典型的前缀匹配

5.strtol字符串转long整数(string to long)

原型和头文件

cs 复制代码
#include <stdlib.h>

long strtol(const char *nptr, char **endptr, int base);

功能

nptr 指向的字符串的起始部分 ,按指定进制 base 转换成 long 类型整数。

转换流程:

  1. 跳过前面的空白字符(空格、\t\n 等);

  2. 读取可选的正负号:+-

  3. 读取符合 base 进制的数字字符;

  4. 遇到第一个"不属于该进制数字"的字符时停止;

  5. 如果 endptr 不是 NULL,就把第一个无效字符的地址 存入 *endptr

    在你的代码中,全部使用:

    cs 复制代码
    strtol(p, &end, 10);

    表示明确按十进制解析,这样即使字符串是 "08",也会被当作合法的十进制 8,不会被误判为八进制。

    1. endptr 机制:这是 strtol 最关键的用法
    cs 复制代码
    strtol(p, &end, 10);
  6. 转换结果存入 count- end 指向数字后面的第一个字符。

  7. 如果字符串是:复制代码

    "20;20260906,1230,..."

    那么:

  8. count = 20

  9. end 指向后面的 ;

6.strtod(string to double)

函数原型

cs 复制代码
#include <stdlib.h>

double strtod(const char *nptr, char **endptr);

二、参数说明

参数 含义
nptr 指向要解析的字符串,例如 "15.5,123.45,45.67;"
endptr 二级指针。函数会把"第一个无法继续解析的字符地址"存入 *endptr。如果不关心结束位置,可以传 NULL,但做协议解析时通常都要用

三、返回值

情况 返回值
成功解析 对应的 double 浮点数值
没有解析到任何数字 返回 0.0,并且 *endptr == nptr(即 end == p
正数溢出 返回 HUGE_VAL,并设置 errno = ERANGE
负数溢出 返回 -HUGE_VAL,并设置 errno = ERANGE
下溢 返回 0.0 或很小的非规格化数,某些实现会设置 ERANGE

7.snprintf

cs 复制代码
/* 把 frame(22B) 和 resp(8B) 拼成一行:"AA 55 ... | 00 00 ..." */
static void BeamHexLine(char *out, const uint8_t *frame, const uint8_t *resp)
{
    uint16_t pos = 0;
    uint8_t  i;
 
    for (i = 0U; i < 22U; i++)
        pos += (uint16_t)snprintf(out + pos, BEAM_HEX_BUF - pos, "%02X", frame[i]);
 
    pos += (uint16_t)snprintf(out + pos, BEAM_HEX_BUF - pos, ",resp=");
 
    for (i = 0U; i < 8U; i++)
        pos += (uint16_t)snprintf(out + pos, BEAM_HEX_BUF - pos, "%02X", resp[i]);
 
    out[pos] = '\0';
}
 
  1. 函数签名
cs 复制代码
static void BeamHexLine(char *out, const uint8_t *frame, const uint8_t *resp)
  • out:输出字符串的缓冲区(char 数组)
  • frame:指向 22 字节数据的指针,通常是发送给天线的控制帧
  • resp:指向 8 字节数据的指针,通常是天线返回的响应帧

  1. 核心语法:snprintf

snprintf 的格式是:

cs 复制代码
int snprintf(char *str, size_t size, const char *format, ...);
  • 它把格式化后的字符串写入 str
  • size当前缓冲区剩余可写的最大字符数 (包括结尾的 \0
  • 返回值是"如果空间足够,实际会写入的字符数 ",也就是格式化结果的长度(不包括结尾的 \0

注意:如果 size 不够大,snprintf 会截断,但返回值仍然是"如果空间足够的长度",而不是实际写入的长度。


  1. 变量 pos 的作用

pos 记录"已经写到了缓冲区 out 的哪个位置",也就是当前偏移量。

每执行一次 snprintf,返回值是本次写入的字符数,把它累加到 pos 上,下一次写入就从新的位置开始。

类似用一个光标向后移动:

cs 复制代码
char buf[100];

int pos = 0;

pos += snprintf(buf + pos, 100 - pos, "Hello");

pos += snprintf(buf + pos, 100 - pos, " World");

执行后 buf"Hello World"pos 是 11。


  1. 逐行解析
cs 复制代码
uint16_t pos = 0; uint8_t i;
  • pos 初始为 0,表示从 out 的第一个字节开始写
  • i 是循环变量,用 uint8_t(0~255)足够,因为循环次数最多 22

第一段循环:写 frame 的 22 个字节

cs 复制代码
for (i = 0U; i < 22U; i++) pos += (uint16_t)snprintf(out + pos, BEAM_HEX_BUF - pos, "%02X", frame[i]);
  • frame[i] 是一个字节(0~255)
  • "%02X" 表示把这个字节格式化为两位大写十六进制 ,不足两位前面补 0
    • 比如 0x0A 输出 "0A",0x3F 输出 "3F"
  • out + pos 是当前写入位置
  • BEAM_HEX_BUF - pos 是剩余缓冲区大小,防止溢出
  • snprintf 返回 2(因为每个字节固定输出 2 个字符),所以 pos 每次加 2

执行完这个循环后,out 的前 44 个字符就是 22 个字节的十六进制表示。


中间:写分隔符

cs 复制代码
pos += (uint16_t)snprintf(out + pos, BEAM_HEX_BUF - pos, ",resp=");
  • 在刚才的十六进制串后面追加 ",resp=",共 6 个字符
  • pos 加 6

第二段循环:写 resp 的 8 个字节

cs 复制代码
for (i = 0U; i < 8U; i++) pos += (uint16_t)snprintf(out + pos, BEAM_HEX_BUF - pos, "%02X", resp[i]);
  • 同理,把 8 个字节写成 16 个字符
  • 每次 pos 加 2

最后补结束符

cs 复制代码
out[pos] = '\0';
  • snprintf 每次都会在写入的字符串末尾自动加 \0,但最后一次之后,我们为了确保整个字符串安全结束,再手动在当前位置放一个 \0
  • 这一步是保险,防止缓冲区末尾没有结束符导致越界读取

  1. 总体效果

假设:

cs 复制代码
frame = {0xAA, 0x55, 0x01, ..., 0x00} (22字节)
resp = {0x00, 0x11, ..., 0xFF} (8字节)

则生成的字符串是:

cs 复制代码
AA5501...00,resp=0011...FF
相关推荐
优信电子1 小时前
STM32 驱动 DHT30 测量环境温湿度(兼容SHT30):从时序解析到完整代码实战
stm32·嵌入式·传感器·sht30·温湿度·环境测量·dht30
小李不想当小白3 小时前
DMA直接存储器存取(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·分享
Zw-awa9 小时前
点亮第一盏 LED:STM32 的 GPIO 到底在控制什么
stm32
Brilliantwxx12 小时前
【STM32】 SPI阻塞式通信与HAL源码(串口读ID实战)
开发语言·stm32·单片机·嵌入式硬件·ecmascript
endeavor1212 小时前
BootLoader与OTA学习(三)
c语言·stm32
zhangzhangkeji12 小时前
stm32 参考文档的目录结构 - 3:STM32F10xxx参考手册(中文).pdf,700多页
stm32·arm
暖焰核心12 小时前
GPIO ——从端口位电路到八种工作模式
stm32
星栖与芯13 小时前
LiteOS-M 切换汇编逐行图解(5):HalPendSV 任务切换的现场搬运(五阶段逐行)
汇编·stm32·嵌入式硬件·harmonyos
LCG元13 小时前
STM32F103 双ADC交错采样实战:DUALMOD寄存器拆解、DMA位宽陷阱与1.71MSPS有效采样率实测
stm32·单片机·嵌入式硬件