Correct usage of snprintf
involves very long and repetitive lines:
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:
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):
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
:
/******************************************************************************
******* 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)):
#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:
char []
) (not vectors or weird things)? I was thinking of using macros, but that sounds interesting. \$\endgroup\$char
array, rather than any other kind, if we want). \$\endgroup\$