0

I would like to expand each argument with their name, following by the value, for example:

#define LOG_VARIABLES(FORMAT, ...) NSLog(FORMAT, ##__VA_ARGS__) //Not sure what to do with ##__VA_ARGS__ here to make it expands like as described below

LOG_VARIABLES(@"%@: %@, %@: %@, %@: %@", arg1, arg2, arg3)

would expand to

STRING_VALUE__(arg1), arg1, STRING_VALUE__(arg2), arg2, STRING_VALUE__(arg3), arg3

so the NSLog print:

arg1: <arg1_value>, arg2: <arg2_value>, arg3: <arg3_value>
Gregor Isack
  • 1,111
  • 12
  • 25

1 Answers1

0

With a bit of help from Overloading Macro on Number of Arguments you could do it something like this.

#define LOG_VARIABLES( FORMAT, ...) NSLog( FORMAT, __VA_ARGS__ )

#define STR(X) #X
#define VAL(X) @(STR(X)), X

#define LOG1( FORMAT, A )                LOG_VARIABLES( FORMAT, VAL( A ) )
#define LOG2( FORMAT, A, B )             LOG_VARIABLES( FORMAT, VAL( A ), VAL( B ) )
#define LOG3( FORMAT, A, B, C )          LOG_VARIABLES( FORMAT, VAL( A ), VAL( B ), VAL( C ) )
#define LOG4( FORMAT, A, B, C, D )       LOG_VARIABLES( FORMAT, VAL( A ), VAL( B ), VAL( C ), VAL( D ) )
#define LOG5( FORMAT, A, B, C, D, E )    LOG_VARIABLES( FORMAT, VAL( A ), VAL( B ), VAL( C ), VAL( D ), VAL( E ) )
#define LOG6( FORMAT, A, B, C, D, E, F ) LOG_VARIABLES( FORMAT, VAL( A ), VAL( B ), VAL( C ), VAL( D ), VAL( E ), VAL( F ) )

#define GET_MACRO( FORMAT, _1, _2, _3, _4, _5, _6, NAME, ... ) NAME
#define LOG_X(FORMAT,...) GET_MACRO(_0, ##__VA_ARGS__, LOG6, LOG5, LOG4, LOG3, LOG2, LOG1 )(FORMAT,__VA_ARGS__)

int main ( int argc, const char * argv [] ) {
    @autoreleasepool
    {
        // insert code here...
        NSLog(@"Hello, World!");

        NSString * a = @"aa";
        NSString * b = @"bb";
        NSString * c = @"cc";
        NSString * d = @"dd";
        NSString * e = @"ee";
        NSString * f = @"ff";

        LOG_X(@"%@:%@",a);
        LOG_X(@"%@:%@ and %@:%@",a,b);
        LOG_X(@"%@:%@ and %@:%@ and %@:%@",a,b,c);
        LOG_X(@"%@:%@ and %@:%@ and %@:%@ and %@:%@",a,b,c,d);
        LOG_X(@"%@:%@ and %@:%@ and %@:%@ and %@:%@ and %@:%@",a,b,c,d,e);
        LOG_X(@"%@:%@ and %@:%@ and %@:%@ and %@:%@ and %@:%@ and %@:%@",a,b,c,d,e,f);

    }
    return 0;
}

Let me hasten to add that there are probably better ways to accomplish what you are trying to do and this is just a sample that only works to 6 arguments, but you get the idea ... also, I started out with your LOG_VARIABLES but along the way it morphed into LOG_X.

skaak
  • 2,988
  • 1
  • 8
  • 16
  • That's pretty good trick, is there any way to generalize the LOG1...LOG6 macros without define each of them if I have, let's say 60 of args? – Gregor Isack Jan 07 '22 at 14:04
  • 1
    I don't think so - preprocessor macros weren't built that way. Even this is a bit of a stretch. I think you could perhaps do it if you used the BOOST lib from the bit of reading I did on this. I'd suggest you stick to this (unless you already use BOOST) but make it more elegant. You can easily incorporate the format string inside LOG1, LOG2 ... for example and other refinements. Also, initially I guess just a few e.g. 10 or 20 will do for most cases. – skaak Jan 07 '22 at 16:10
  • 1
    I see, thanks for the input! – Gregor Isack Jan 07 '22 at 16:44