Typically, when I need to do debug output in Windows, I use the following C code segment:

```
#ifdef _DEBUG
#define DBGPRINT( kwszDebugFormatString, ... ) \
{ \
    wprintf_s( L"[%s:%d] ", __FUNCTIONW__, __LINE__ ); \
    wprintf_s( kwszDebugFormatString, __VA_ARGS__ ); \
}
#else
#define DBGPRINT( kwszDebugFormatString, ...) ;;
#endif

```

I'd like to recode this to use `OutputDebugString` which doesn't accept a format string. I consider statically allocating a small array on the stack (e.g., `WCHAR wszBuf[100] = {0};`) to be somewhat crude since it might consume significantly more or less memory than what is allocated and either truncate output or waste memory. I wrote the following code that addresses all of these concerns, but concerns me because the macro is a bit large.

```
#ifdef _DEBUG
#define DBGPRINT( kwszDebugFormatString, ... ) \
{ \
    INT iLineNumber = __LINE__; \
    FILE *fileNul = NULL; \
    INT cbFormatString = 0; \
    PWCHAR wszDebugString = NULL; \
    size_t st_Offset = 0; \
    \
    /* Determine the number of characters in the format string by writing to NUL. */\
    fopen_s( &fileNul, "nul", "w" ); \
    cbFormatString = fwprintf_s( fileNul, L"[%s:%d]", __FUNCTIONW__, iLineNumber ) * sizeof( WCHAR ); \
    cbFormatString += fwprintf_s( fileNul, kwszDebugFormatString, __VA_ARGS__ ) * sizeof( WCHAR ) + 2; \
    \
    /* Depending on the size of the format string, allocate space on the stack or the heap. */ \
    wszDebugString = (PWCHAR)_malloca( cbFormatString ); \
    \
    /* Populate the buffer with the contents of the format string. */ \
    StringCbPrintfW( wszDebugString, cbFormatString, L"[%s:%d]", __FUNCTIONW__, iLineNumber ); \
    StringCbLengthW( wszDebugString, cbFormatString, &st_Offset ); \
    StringCbPrintfW( &wszDebugString[st_Offset / sizeof(WCHAR)], cbFormatString - st_Offset, kwszDebugFormatString, __VA_ARGS__ ); \
    \
    OutputDebugStringW( wszDebugString ); \
    \
    _freea( wszDebugString ); \
    fclose( fileNul ); \
}
#else
#define DBGPRINT( kwszDebugFormatString, ... ) ;;
#endif

```

A few notes:

* I used \_malloca() and \_freea() so that stack allocations could be used if the output should be small enough.
* I'm not aware of any way to get the correct size of a fully expanded format string. The best solution I could come up with was to dump it to NUL and calculate the correct sizes from there.
* I used a macro because I don't believe there is a simple way to achieve the same result when using a function.

My question is, quite simply, would this macro be considered bad practice for one reason or another (particularly for size or inefficiency)? If so, what alternatives should I be considering?

Solution
--------

In case anyone else is wondering, I used the suggestions from the comments and the selected answer and came up with the following code. Thank you so much to everyone who commented or answered - feel free to add more if you have a clever way of doing this that you want to share!

```
#ifdef _DEBUG
#define DBGPRINT(kwszDebugFormatString, ...) _DBGPRINT(__FUNCTIONW__, __LINE__, kwszDebugFormatString, __VA_ARGS__)

VOID _DBGPRINT( LPCWSTR kwszFunction, INT iLineNumber, LPCWSTR kwszDebugFormatString, ... ) \
{
    INT cbFormatString = 0;
    va_list args;
    PWCHAR wszDebugString = NULL;
    size_t st_Offset = 0;

    va_start( args, kwszDebugFormatString );

    cbFormatString = _scwprintf( L"[%s:%d] ", kwszFunction, iLineNumber ) * sizeof( WCHAR );
    cbFormatString += _vscwprintf( kwszDebugFormatString, args ) * sizeof( WCHAR ) + 2;

    /* Depending on the size of the format string, allocate space on the stack or the heap. */
    wszDebugString = (PWCHAR)_malloca( cbFormatString );

    /* Populate the buffer with the contents of the format string. */
    StringCbPrintfW( wszDebugString, cbFormatString, L"[%s:%d] ", kwszFunction, iLineNumber );
    StringCbLengthW( wszDebugString, cbFormatString, &st_Offset );
    StringCbVPrintfW( &wszDebugString[st_Offset / sizeof(WCHAR)], cbFormatString - st_Offset, kwszDebugFormatString, args );

    OutputDebugStringW( wszDebugString );

    _freea( wszDebugString );
    va_end( args );
}
#else
#define DBGPRINT( kwszDebugFormatString, ... ) ;;
#endif

```