This is the code that Toby Speight suggested in his answer:
/*
* int sbprintf(char buff[restrict], int *restrict written,
* const char *restrict format, ...);
*/
#define sbprintf(buff, written, format, ...) ( \
{ \
int len_; \
\
alx_static_assert_array(buff); \
\
len_ = snprintf((buff), sizeof(buff), format, ##__VA_ARGS__);\
if (written != NULL) \
*written = len_; \
len_ >= (int)sizeof(buff); \
} \
)
I have tested it and works as expected:
- If
written
isNULL
it doesn't write into it. - The return value is
true
when the string is truncated andfalse
otherwise. - It doesn't compile if
buff
is not an array. - It accepts a variable number of arguments after
format
, including no arguments.
The comment above the macro is the prototype that a user should see, to better understand the usage, although a real function with that prototype wouldn't work because of the array decaying to a pointer.
Comments about the style:
I tried to follow the Linux Kernel Coding Style, but there have been exceptions:
if (written != NULL)
is used instead of if (written)
to avoid the compiler complaining:
main.c:22:23: error: the address of ‘w1’ will always evaluate as ‘true’ [-Werror=address]
if (alx_sbprintf(b1, &w1, test))
^
.../libalx/base/stdio/sbprintf.h:36:6: note: in definition of macro ‘alx_sbprintf’
if (written) \
^~~~~~~
EDIT:
Given that snprintf
sets errno
(at least in POSIX), it would be good to set errno
to ENOMEM
on truncation.