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 的公开打包规则, 不要直接依赖早期文章中的私有结构和标志值。

上游依据