2

I have these macros which generate error in Visual Studio 2015.

#define log_params  __FILE__, __LINE__
#define log(file, line, message, ...) _snprintf_s(nullptr, 0, 0, message,  __VA_ARGS__)

Now calling this never works

 log(log_params, "testing %d", 4)

Any thoughts? I also checked output of preprocessor and it is:

_snprintf_s(nullptr, 0, 0, 4 );

EDIT 1 Intresting finding

#define log(file, line, message, ...) file line

will produce this :

"service.cpp", 164 "testing %d"

Is it normal?

Roozbeh G
  • 427
  • 4
  • 18
  • 2
    log is a macro expecting (at least) 4 arguments. – Arif Burhan Oct 12 '16 at 17:55
  • I'm getting `_snprintf_s(nullptr, 0,0,4, );` which makes sense. Are you sure the output of the preprocessor was copy/pasted correctly? – user3386109 Oct 12 '16 at 18:00
  • That's not C, but C++. – too honest for this site Oct 12 '16 at 18:04
  • 1
    @ArifBurhan While a variadic macro with an empty variadic list is forbidden by the standard, it's supported as an extension by most compilers (where an empty variadic list is treated as a list with zero tokens). [_However_, there's no consensus on how to support this](https://en.wikipedia.org/wiki/Variadic_macro#Trailing_comma). Visual Studio is surprisingly polite, and swallows the comma without requiring special syntax. GCC uses the syntax `##__VA_ARGS__`, instead of the standard `__VA_ARGS__`, to indicate that the comma should be swallowed in case of zero-token variadic lists. – Justin Time - Reinstate Monica Oct 12 '16 at 18:19
  • I am actually getting `_snprintf_s(nullptr, 0, 0, 4 ) ` but I am guessing I should get `_snprintf_s(nullptr, 0, 0, "testing $d",4 )`, right? – Roozbeh G Oct 12 '16 at 18:22

2 Answers2

4

The following invocation:

log(log_params, "testing %d", 4)

calls function-like macro log with three actual arguments. Their replacements are not resolved before arguments are "passed" to the macro. In other words, even if log_params contains comma by itself, this comma is not taken into account during function-like macro call resolution.

Thus, you are effectively passing arguments as:

file    ---> __FILE__, __LINE__
line    ---> "testing %d"
message ---> 4

First two parameters are ignored by the replacement, and eventually you obtain:

_snprintf_s(nullptr, 0, 0, 4,  __VA_ARGS__)

which in turns become (as MSVC is happy to ignore requirement for at least one variadic argument):

_snprintf_s(nullptr, 0, 0, 4)
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
3

This solved my problem

__VA_ARGS__ expansion using MSVC

so now I am using

 #define EXPAND( x ) x
 #define Log_printf( file_name,line, message,...)  _snprintf_s(nullptr, 0,0,message, __VA_ARGS__)
 #define Log(...) EXPAND (Log_printf(__VA_ARGS__))
Community
  • 1
  • 1
Roozbeh G
  • 427
  • 4
  • 18