cbprintf 与格式化打包
本页依据 文档基线与后续更新 中记录的 Zephyr main 快照更新。
cbprintf 将格式字符串与参数转换成字符,通过应用回调输出,避免要求整个格式化结果
先放进一个大缓冲区。接口位于 <zephyr/sys/cbprintf.h>。
同步格式化
回调类型是 int (*cbprintf_cb)(int c, void *ctx)。
cbprintf() 接收可变参数,cbvprintf() 接收 va_list。
回调负返回值会导致格式化返回错误;正常情况下函数返回生成的字符数。
下面通过 C 库字符输出展示回调接口:
#include <zephyr/sys/cbprintf.h>
#include <stdio.h>
static int emit_character(int c, void *ctx)
{
return fputc(c, (FILE *)ctx);
}
int report_temperature(int value)
{
return cbprintf(emit_character, stdout, "temperature=%d\n", value);
}
实际应用也可把回调接到设备、压缩器或协议编码器,回调上下文和存储必须在调用期间有效。 以上示例仍使用 libc 输出;是否节省格式化代码取决于实际链接配置。
snprintfcb() / vsnprintfcb() 提供内存格式化接口。
截断语义仍应按照返回长度与缓冲区容量判断,而不是假设调用成功就装下了整个字符串。
配置与格式支持
CONFIG_CBPRINTF_FULL_INTEGRAL/CONFIG_CBPRINTF_REDUCED_INTEGRAL:整数功能范围。CONFIG_CBPRINTF_FP_SUPPORT:浮点转换支持。CONFIG_CBPRINTF_FP_A_SUPPORT、CONFIG_CBPRINTF_FP_ALWAYS_A:十六进制浮点相关行为。CONFIG_CBPRINTF_N_SPECIFIER:控制%n支持。CONFIG_CBPRINTF_LIBC_SUBSTS:提供相关 libc 替代实现。CONFIG_CBPRINTF_NANO:更小但功能受限的格式化实现。
不能在开启 nano 模式后仍保证完整 C99 格式支持。浮点、宽度、精度、格式 flags 和 长整数支持,应结合所选配置与 C 库确认。格式与参数不匹配同样是调用者错误。
延后格式化 package
日志等场景先捕获格式字符串和参数,再在稍后格式化。 cbprintf package 描述这个待处理状态,创建后不等于已经取得最终输出文本。
Transient:保存参数与相关位置,仍依赖外部字符串保持有效。
Self-contained:复制可变字符串,仍可能引用只读字符串。
Fully self-contained:把所需字符串全部包含在 package 中。
运行时打包通过 cbprintf_package() / cbvprintf_package() 分析格式。
静态打包宏利用 C11 的类型能力,通常更快,但对字符指针代表字符串还是地址存在限制。
用 %p 输出字符指针时明确转换为 void *,避免被当成 %s 处理。
转换、对齐与所有权
根据打包时记录的信息,可以使用 package copy/convert 接口增加字符串内容,
转换为更完整的自包含包。变体之间的转换需要先计算空间,并保证目的内存的对齐。
与 va_list 布局有关的 package 不应当作跨架构、跨固件永久不变的序列化格式。
CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE 和
CONFIG_CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT 会影响打包行为。
在异步使用、复制或移交 package 前,确认格式串、参数中指针、附加字符串以及包本身
的生命周期。使用 Zephyr logger 时优先遵循 logger 的公开打包规则,
不要直接依赖早期文章中的私有结构和标志值。