3

The method I am trying to call is;

- (void)addLogWithLevel:(MDCLogLevel)logLevel logContent:(NSString *)logContent, ...
{
    va_list args;
    va_start(args, logContent);
    NSString *message = [[NSString alloc] initWithFormat:logContent
                                               arguments:args];
    va_end(args);
    MDCLog *log = [MDCLog logWithContent:message content:logLevel];
    [self.deviceLogs addObject:log];
}

I have defined the macro as;

#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:(__VA_ARGS__)];

I have tried various formats of this macro, but nothing seems to work.

If I am to call;

MDCLogDebug(@"Test:%@", @"Hey");

All I see in the console is;

Hey

Where am I going wrong? I'm new to using Variadic methods and my C isn't so great!

David Costa
  • 1,738
  • 18
  • 33
MattCheetham
  • 430
  • 1
  • 5
  • 10

1 Answers1

12

Actually, your problem is not really related to Objective-C directly, but to C itself, as macros are plain C preprocessor directives.

In a macro, __VA_ARGS__ represents the arguments that are placed instead of the ....

So in your call to MDCLogDebug(@"Test:%@", @"Hey"), the format argument is @"Test:%@" and __VA_ARGS__ represents the rest of the arguments afterwards, namely simply @"Hey" in your case.

If you want to pass both the @"Test:%@" and @"Hey" as arguments to logContent:, you have to explicitly tell it so, using:

#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:format, __VA_ARGS__]

Note: An even better solution would be to use the ## prefix before __VA_ARGS__ so that the comma won't be added if __VA_ARGS__ is empty (namely if you only pass a format argument but nothing afterwards, like MDCLogDebug(@"Foo")):

#define MDCLogDebug(format, ...) [[MDCLogController sharedController] \
                                  addLogWithLevel:MDCLogLevelDebug \
                                       logContent:format, ## __VA_ARGS__]

(Note: I use backslashes in this last macro definition above to allow the macro to be written on multiple lines, instead of writing it on one single big long line)

For more information, see the official GCC documentation about Variadic Macros here.

AliSoftware
  • 32,623
  • 6
  • 82
  • 77
  • Hey thanks for the reply. Correcting the line to `#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:(format, ##__VA_ARGS__)];` doesn't fix the problem either. I'm still seeing "Hey" in the console where I'm hoping to see "Test:Hey". The macro should work exactly like NSLog does. The `NSString *message` doesn't appear to be putting the format and arguments together correctly? – MattCheetham Feb 02 '14 at 15:50
  • 2
    I think the parentheses in `logContent:(format, __VA_ARGS__)` are wrong. It should be `#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:format, ##__VA_ARGS__]`. And you should not append a semi-colon to the macro definition! – Martin R Feb 02 '14 at 16:04
  • 1
    Martin is correct. With the parentheses, there's a single method argument which is an expression using the comma operator rather than being a list of method arguments. So, each subexpression is evaluated in order, but the overall expression takes the value of the last subexpression. And the semicolon will be provided at the macro use site, like the question showed, so it shouldn't be in the macro. Having it in the macro can screw up `if`-`else` statements. – Ken Thomases Feb 02 '14 at 16:08
  • I edited my answer to remove the parenthesizes (I didn't try my code and wrote it on the fly directly on SO). Thanks @MartinR for the remark. Also removed the semicolon that I copy/pasted without even noticing, whereas as explained by others you shouldn't add to the macro itself. _(PS: if this answer solved your question, don't forget to mark it as accepted on SO, to tell others that your question already got a solution)_ – AliSoftware Feb 02 '14 at 18:03