This is the code that **Toby Speight** suggested in his answer: ```c /* * 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` is `NULL` it doesn't write into it. - The return value is `true` when the string is truncated and `false` 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][1]), it would be good to set `errno` to `ENOMEM` on truncation. ________________________________________________________ **EDIT:** This version includes the improvements suggested by **Toby Speight** and **chux**, as well as setting `errno` on error. The code is GCC (or Clang) specific. I doubt it's doable (with the same level of safety and clarity) in standard C, although a standard solution would be nice. Properties: - If `written` is `NULL` it doesn't write into it. - It doesn't compile if `buff` is not an array. - It accepts a variable number of arguments after `format`, including no arguments. - Sets `errno` on any error. - If there's a `snprintf` internal error, the error code is negative (`-errno`), and `written` is also negative. - If the string is truncated, the error code is positive (`ENOMEM`). - If the error code is negative, the string should not be trusted; if it's positive, it's been truncated, but it's a valid string. Code: ```c /* * int alx_sbprintf(char buff[restrict], int *restrict written, * const char *restrict format, ...); */ #define alx_sbprintf(buff, written, format, ...) ( \ { \ int len_; \ int err_; \ \ alx_static_assert_array(buff); \ err_ = 0; \ \ len_ = snprintf(buff, sizeof(buff), format, ##__VA_ARGS__); \ if (written != NULL) \ *written = len_; \ \ if (len_ < 0) { \ err_ = -errno; \ goto ret_; \ } \ if ((uintmax_t)len_ >= sizeof(buff)) { \ errno = ENOMEM; \ err_ = ENOMEM; \ goto ret_; \ } \ ret_: \ err_; \ } \ ) ``` [1]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html