doc/services/formatted_output.rst
.. _formatted_output:
Formatted Output ################
Applications as well as Zephyr itself requires infrastructure to format
values for user consumption. The standard C99 library *printf()
functionality fulfills this need for streaming output devices or memory
buffers, but in an embedded system devices may not accept streamed data
and memory may not be available to store the formatted output.
Internal Zephyr API traditionally provided this both for
:c:func:printk and for Zephyr's internal minimal libc, but with
separate internal interfaces. Logging, tracing, shell, and other
applications made use of either these APIs or standard libc routines
based on build options.
The :c:func:cbprintf public APIs convert C99 format strings and
arguments, providing output produced one character at a time through a
callback mechanism, replacing the original internal functions and
providing support for almost all C99 format specifications. Existing
use of s*printf() C libraries in Zephyr can be converted to
:c:func:snprintfcb() to avoid pulling in libc implementations.
Several Kconfig options control the set of features that are enabled, allowing some control over features and memory usage:
CONFIG_CBPRINTF_FULL_INTEGRAL
or :kconfig:option:CONFIG_CBPRINTF_REDUCED_INTEGRALCONFIG_CBPRINTF_FP_SUPPORTCONFIG_CBPRINTF_FP_A_SUPPORTCONFIG_CBPRINTF_FP_ALWAYS_ACONFIG_CBPRINTF_N_SPECIFIER:kconfig:option:CONFIG_CBPRINTF_LIBC_SUBSTS can be used to provide functions
that behave like standard libc functions but use the selected cbprintf
formatter rather than pulling in another formatter from libc.
In addition :kconfig:option:CONFIG_CBPRINTF_NANO can be used to revert back to
the very space-optimized but limited formatter used for :c:func:printk
before this capability was added.
.. _cbprintf_packaging:
Cbprintf Packaging
Typically, strings are formatted synchronously when a function from printf
family is called. However, there are cases when it is beneficial that formatting
is deferred. In that case, a state (format string and arguments) must be captured.
Such state forms a self-contained package which contains format string and
arguments. Additionally, package may contain copies of strings which are
part of a format string (format string or any %s argument). Package primary
content resembles va_list stack frame thus standard formatting functions are
used to process a package. Since package contains data which is processed as
va_list frame, strict alignment must be maintained. Due to required padding,
size of the package depends on alignment. When package is copied, it should be
copied to a memory block with the same alignment as origin.
Package can have following variants:
Package can be created using two methods:
cbprintf_package or :c:func:cbvprintf_package. This
method scans format string and based on detected format specifiers builds the
package._Generic keyword (C11 feature) to be supported by
the compiler and cannot distinguish between %p and %s if char pointer
is used. It treats all (unsigned) char pointers as %s thus it will attempt
to append string to a package. It can be handled correctly during conversion
from transient package to self-contained package using
:c:macro:CBPRINTF_PACKAGE_CONVERT_PTR_CHECK flag. However, it requires access
to the format string and it is not always possible thus it is recommended to
cast char pointers used for %p to void *. There is a logging warning
generated by :c:func:cbprintf_package_convert called with
:c:macro:CBPRINTF_PACKAGE_CONVERT_PTR_CHECK flag when char pointer is used with
%p.Several Kconfig options control behavior of the packaging:
CONFIG_CBPRINTF_PACKAGE_LONGDOUBLECONFIG_CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENTIt is possible to convert package to a variant which contains more information, e.g
transient package can be converted to self-contained. Conversion to
fully self-contained package is possible if :c:macro:CBPRINTF_PACKAGE_ADD_RO_STR_POS
flag was used when package was created.
:c:func:cbprintf_package_copy is used to calculate space needed for the new
package and to copy and convert a package.
Format of the package contains paddings which are platform specific. Package consists
of header which contains size of package (excluding appended strings) and number of
appended strings. It is followed by the arguments which contains alignment paddings
and resembles va_list stack frame. It is followed by data associated with character
pointer arguments used by the string which are not appended to the string (but may
be appended later by :c:func:cbprinf_package_convert). Finally, package, optionally,
contains appended strings. Each string contains 1 byte header which contains index
of the location where address argument is stored. During packaging address is set
to null and before string formatting it is updated to point to the current string
location within the package. Updating address argument must happen just before string
formatting since address changes whenever package is copied.
+------------------+-------------------------------------------------------------------------+ | Header | 1 byte: Argument list size including header and fmt (in 32 bit words) | | +-------------------------------------------------------------------------+ | sizeof(void *) | 1 byte: Number of strings appended to the package | | +-------------------------------------------------------------------------+ | | 1 byte: Number of read-only string argument locations | | +-------------------------------------------------------------------------+ | | 1 byte: Number of transient string argument locations | | +-------------------------------------------------------------------------+ | | platform specific padding to sizeof(void *) | +------------------+-------------------------------------------------------------------------+ | Arguments | Pointer to fmt (or null if fmt is appended to the package) | | +-------------------------------------------------------------------------+ | | (optional padding for platform specific alignment) | | +-------------------------------------------------------------------------+ | | argument 0 | | +-------------------------------------------------------------------------+ | | (optional padding for platform specific alignment) | | +-------------------------------------------------------------------------+ | | argument 1 | | +-------------------------------------------------------------------------+ | | ... | +------------------+-------------------------------------------------------------------------+ | String location | Indexes of words within the package where read-only strings are located | | information +-------------------------------------------------------------------------+ | (optional) | Pairs of argument index and argument location index where transient | | | strings are located | +------------------+-------------------------------------------------------------------------+ | Appended | 1 byte: Index within the package to the location of associated argument | | strings +-------------------------------------------------------------------------+ | (optional) | Null terminated string | | +-------------------------------------------------------------------------+ | | ... | +------------------+-------------------------------------------------------------------------+
.. warning::
If :kconfig:option:CONFIG_MINIMAL_LIBC is selected in combination with
:kconfig:option:CONFIG_CBPRINTF_NANO formatting with C standard library
functions like printf or snprintf is limited. Among other
things the %n specifier, most format flags, precision control, and
floating point are not supported.
.. _cbprintf_packaging_limitations:
_Generic support is required by the compiler to use static (fast) packaging.%p format specifier to
other pointer type (e.g. void *). If format string is not accessible then only
static packaging is possible and it will append all detected strings. Character pointer
used for %p will be considered as string pointer. Copying from unexpected location
can have serious consequences (e.g., memory fault or security violation).API Reference
.. doxygengroup:: cbprintf_apis