docs/Writerside/topics/printf.h.md

Sat, 15 Feb 2025 17:43:21 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 15 Feb 2025 17:43:21 +0100
changeset 1210
2ad0cf0f314b
parent 1172
1a6aa0301226
permissions
-rw-r--r--

complete the printf documentation and fix code formatting

relates to #451

# Formatting

In the `printf.h` header you can find various useful `printf()`-like functions that can write the formatted output
directly to an arbitrary stream or [buffer](buffer.h.md), or to memory allocated by an [allocator](allocator.h.md).

With the help of these convenience functions, you do not need the libc `snprintf` to print your string to a temporary buffer anymore,
plus you do not need to worry about too small buffer sizes, because the functions will automatically allocate enough memory to contain the entire formatted string.

> Although UCX usually uses `size_t` for sizes, the return type of all `printf`-like functions
> (except for the `cx_asprintf()` family of functions) is `int`, consistent with the stdio `printf` return type.
{style="note"}

## Print to Streams and Buffers

```C
#include <cx/printf.h>

int cx_fprintf(void *stream, cx_write_func wfc,
        const char *fmt, ...);

int cx_vfprintf(void *stream, cx_write_func wfc,
        const char *fmt, va_list ap);

int cx_bprintf(CxBuffer *buf, const char *fmt, ...);
```

The `cx_fprintf()` function uses the stdio `snprintf()` to prepare a formatted string
which is then written to the `stream` using the write function `wfc`.
The return value is the number of bytes written or a value less than zero when an error occurred.
If the resulting string is short enough, no additional memory is allocated on the heap.
See the Section about [](#small-buffer-optimization) for more details.

The `cx_vfprintf()` function is equivalent to `cx_fprintf()`,
except that instead of being called with a variable number of arguments,
it is called with an argument list as defined by `<stdarg.h>`.

The `cx_bprintf()` function is implemented as macro for `cx_fprintf()` with the
`CxBuffer` as `stream` and the `cxBufferWriteFunc` as write function.

## Print to Freshly Allocated Memory

```C
#include <cx/printf.h>

cxmutstr cx_asprintf(const char *fmt, ...);

cxmutstr cx_asprintf_a(const CxAllocator *allocator,
        const char *fmt, ...);

cxmutstr cx_vasprintf(const char *fmt, va_list ap);

cxmutstr cx_vasprintf_a(const CxAllocator *allocator,
        const char *fmt, va_list ap);
```

The `cx_asprintf()` and `cx_asprintf_a()` functions print the formatted output directly to a freshly allocated
string which is then returned from the function.
On platforms (or when using allocators) where allocation can fail,
the returned string may be empty and the `ptr` field set to `NULL`. 

The `cx_vasprintf()` and `cx_vasprintf_a()` functions are equivalent to `cx_asprintf()` and `cx_asprintf_a()`,
except that instead of being called with a variable number of arguments,
they are called with an argument list as defined by `<stdarg.h>`.

## Print to Existing Memory

```C
#include <cx/printf.h>

int cx_sprintf(char **str, size_t *len,
        const char *fmt, ...);

int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len,
        const char *fmt, ...);

int cx_sprintf_s(char *buf, size_t *len, char **str,
        const char *fmt, ...);

int cx_sprintf_sa(CxAllocator *alloc,
        char *buf, size_t *len, char **str,
        const char *fmt, ...);

int cx_vsprintf(char **str, size_t *len,
        const char *fmt, va_list ap);

int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len,
        const char *fmt, va_list ap);

int cx_vsprintf_s(char *buf, size_t *len, char **str,
        const char *fmt, ...);

int cx_vsprintf_sa(CxAllocator *alloc,
        char *buf, size_t *len, char **str,
        const char *fmt, va_list ap);
```

The `cx_sprintf()` and `cx_sprintf_a()` functions take a pointer `str` to a pointer to a pre-allocated buffer,
as well as a pointer `len` to `*str`'s length.
If the formatted output would not fit into this buffer, it is reallocated
and the new pointer to the buffer and the new length are written back to the variables pointed to by `str` and `len`.

The `cx_sprintf_s()` and `cx_sprintf_sa()` functions differ from the previous function in that they take
the pointer to the pre-allocated buffer in the `buf` argument and not in the `str` argument
(which in this case is only used for storing the resulting pointer), and _always_ allocate an entirely new buffer
when the length is insufficient.
This is particularly useful when you want to print the formatted string to a buffer allocated on the stack, but also
want the option to switch to heap-allocated memory when necessary.

In other words: when the formatted output fits into the buffer pointed to by `buf`, `buf` will be written to `*str`.
Otherwise, the pointer to the freshly allocated buffer is written to `*str`.

> When using `cx_sprintf()` or `cx_sprintf_a()` you should always make sure that the string pointed to by `*str`
> was allocated by a matching allocator.
> This restriction does not apply for `cx_sprintf_s()` or `cx_sprintf_sa()` which would allocate a fresh buffer when needed.

The `cx_vsprintf()`, `cx_vsprintf_a()`, `cx_vsprintf_s()`, and `cx_vsprintf_sa()` functions are equivalent
to `cx_sprintf()`, `cx_sprintf_a()`, `cx_sprintf_s()`, and `cx_sprintf_sa()`,
except that instead of being called with a variable number of arguments,
they are called with an argument list as defined by `<stdarg.h>`.

## Small Buffer Optimization

All functions that allocate internal temporary memory use small buffer optimization to avoid a heap allocation
if the expected string length is smaller than `cx_printf_sbo_size`.
This size cannot be changed at runtime, but modified by defining the `CX_PRINTF_SBO_SIZE` macro when [building](install.md#small-buffer-optimizations) the library.

<seealso>
<category ref="apidoc">
<a href="https://ucx.sourceforge.io/api/printf_8h.html">printf.h</a>
</category>
</seealso>

mercurial