Encapsulating snprintf to avoid repetition of sizeof Correct usage of snprintf involves very long and repetitive lines:

if (snprintf(buff, sizeof(buff), format, ...) &gt;= (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, ...) &gt;= 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 &lt;stdio.h&gt;

#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__) &gt;= SSIZEOF(buff) \
}                                                                       \
)


/******************************************************************************
 ******* include guard ********************************************************
 ******************************************************************************/
#endif      /* libalx/base/stdio/sbprintf.h */


Used macros (defined in other headers from my library (libalx)):

#include &lt;assert.h&gt;

#include &lt;sys/types.h&gt;


#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), &amp;(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)
Pedantically, if (snprintf(buff, sizeof(buff), format, ...) &gt;= SSIZEOF(buff)) goto err; is an insufficient test.  Test for &lt; 0 is also needed.


  The snprintf function returns the number of characters that would have been written
  had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred....
  C111 §7.21.6.5 3




Note that ssize_t itself is not in standard C. 



To cope with both issues, perform 2 sided test and drop using ssize_t.

int i = snprintf(buff, sizeof(buff), format, ...);
if (i &lt; 0 || (unsigned) i &gt;= sizeof(buff)) goto err;


... or if INT_MAX &lt;= UINT_MAX/2 (a very common implementation), code can cheat with a one sided test as i&lt;0 coverts to a large unsigned.  Again no need for ssize_t.

int i = snprintf(buff, sizeof(buff), format, ...);
if ((unsigned) i &gt;= sizeof(buff)) goto err;