Correct usage of `snprintf` involves very long and repetitive lines: ```c if (snprintf(buff, sizeof(buff), format, ...) >= (int)sizeof(buff)) goto err; ``` I first encapsulated this macro: `#define SSIZEOF(x) ((ssize_t)sizeof(x))`. The result is I now have a slightly shorter line: ```c if (snprintf(buff, sizeof(buff), format, ...) >= SSIZEOF(buff)) goto err; ``` But I'm not yet happy. Writing `sizeof` twice is still very long and annoying, and more if the buffer has a relatively long name. I decided to do a macro that behaves this way (with the same exact safety) (The `b` in the name stands for buffer): ```c if (sbprintf(buff, format, ...)) goto err; ``` It needs to be a macro to avoid the array decaying to a pointer, so that I can still use `sizeof(buff)` inside the macro. ____________________________________________ `sbprintf.h`: ```c /****************************************************************************** ******* include guard ******************************************************** ******************************************************************************/ #ifndef ALX_STDIO_SBPRINTF_H #define ALX_STDIO_SBPRINTF_H /****************************************************************************** ******* headers ************************************************************** ******************************************************************************/ #include <stdio.h> #include "libalx/base/assert/assert.h" #include "libalx/base/compiler/size.h" /****************************************************************************** ******* macros *************************************************************** ******************************************************************************/ /* int sbprintf(char buff[restrict], const char *restrict format, ...); */ #define sbprintf(buff, format, ...) ( \ { \ alx_static_assert_array(buff); \ \ snprintf(buff, sizeof(buff), format, ##__VA_ARGS__) >= SSIZEOF(buff) \ } \ ) /****************************************************************************** ******* include guard ******************************************************** ******************************************************************************/ #endif /* libalx/base/stdio/sbprintf.h */ ``` Used macros (defined in other headers from my library (libalx)): ```c #include <assert.h> #include <sys/types.h> #define alx_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) #define alx_static_assert_array(a) do \ { \ static_assert(!alx_same_type((a), &(a)[0]), "Not an array!"); \ } while (0) #define SSIZEOF(x) ((ssize_t)sizeof(x)) ``` ________________________________ I use GCC8 and C17 (`gcc -std=gnu17 -Wall -Wextra -Werror`), but if there is any easy and not very ugly fix that helps portability, it is welcome. The same about C++: This is about C (I'll ask the same question about C++ after this one has been answered), but if there is any fix that would improve compatibility with C++, it is also welcome. What do you think about `sbprintf`? Feel free to comment the other macros, of course! **EDIT:** The actual name of the macro in my library is `alx_sbprintf` to avoid using a name that may end up being used by a future implementation. __________________________________________ Related links: - [How to make a variadic macro (variable number of arguments)][1] [1]: https://stackoverflow.com/a/679993/6872717