2

I am learning how to use macro but now confused with one.

I am trying to create a NSString concatenate which will just append every params to each other.

for example : concatOP(@"hey",@"Jude",@"Don't") would return a NSString containing : @"heyJudeDon't"

I actually made a bit of code (some found here as well) which get the number of params but I don't succeed to make the second part of the job.

#define NUMARGS(...)        ( sizeof((int[]){__VA_ARGS__}) / sizeof(int) )
#define concatOP(...)       NSMutableString *format = [[NSMutableString alloc] init];\
                            for( int i = 0; i < NUMARGS(__VA_ARGS__); i++){\
                            [format appendString:@"%@"];}\
                            [[NSString alloc] initWithFormat:format, __VA_ARGS__]

I actually get many errors, telling me that format doesn't exist or that I miss some ";" or other ending tags.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Clad Clad
  • 2,653
  • 1
  • 20
  • 32
  • 3
    I don't know if this is an arbitrary example or the real problem you're trying to solve, but often people use `NSArray` method `componentsJoinedByString` for this sort of concatenation. So `NSString *result = [@[@"Hey",@"Jude",@"Don't"] componentsJoinedByString:@""];`. – Rob Jan 22 '14 at 13:40
  • Why did I get a -1 ? :/ – Clad Clad Jan 22 '14 at 14:31
  • It could have been down-voted because the proposed macro suffers such fundamental issues (as Cy-4AH's expansion illustrates, while your intent was clear, the proposed execution doesn't make any sense) and even if it did, I'm not sure this is a very good application of macros in the first place. Still, I'm not sure it deserved the down-vote (it got me digging around in variadic macros, so I learned something). I wouldn't sweat the down-vote. – Rob Jan 22 '14 at 15:21
  • The intent of this website is to help people so maybe the question can seems easy for some but it's not obvious when we arrive to some questions about variadic and preprocessor instructions... So sorry not to know everything it's my biggest mistake :/ I still think my question is still worth it because I learn some things and I am sure I am not the only one. – Clad Clad Jan 22 '14 at 15:44
  • No offense was intended. I was just explaining why someone might have down-voted. I don't think you need to delete this, either. – Rob Jan 22 '14 at 15:57
  • 1
    It's not for you sorry ;) thanks for your explanation :) – Clad Clad Jan 22 '14 at 16:01

3 Answers3

8

Here is yours macro:

#define concatOP(...) [@[__VA_ARGS__] componentsJoinedByString:@""]

EDIT: if you unwind yours macro NSString* result = concatOP(@"hey",@"Jude",@"Don't"); you will get:

NSString* result = NSMutableString *format = [[NSMutableString alloc] init]; for( int i = 0; i < NUMARGS(@"hey",@"Jude",@"Don't"); i++){ format = [format appendString:@"%@"];} [[NSString alloc] initWithFormat:format, @"hey",@"Jude",@"Don't"];

Looks odd.

Cy-4AH
  • 4,370
  • 2
  • 15
  • 22
  • This actually works like a charm but I still don't get why my code don't work (even if your is better because way more simple). Do you have any idea about that ? – Clad Clad Jan 22 '14 at 13:51
  • @CladClad you can't find `__VA_ARGS__`s number of argument with yours macro. Look this: http://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments – Cy-4AH Jan 22 '14 at 13:53
  • 1
    NUMARGS works in order to find the number of argument I tried it ;) It actually comes from the post you just gave ;) – Clad Clad Jan 22 '14 at 14:00
  • my bad for the `format =` it was a old test. Actually I am just trying to get the format for the output so something like @"%@%@" if there are 2 args etc but maybe it's a foolish way to do it ^^ – Clad Clad Jan 22 '14 at 14:21
3

This doesn't exactly answer your question, but NSString literals are concatenated by the compiler, just like their C-counterparts, so this code works out of the box:

NSString *str = @"Hey" @"Jude" @"Don't";

which is the same as:

NSString *str = @"HeyJudeDon't";

This is typically used to split a long string literal across multiple lines of the source file.

Bottom line; you don't need all those messy macros and pointless methods to do this.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • really :'( thanks for that also I learned something quite useful thanks to you. I think I will remember it FOREVER :s Thanks a lot for that ;) – Clad Clad Jan 22 '14 at 14:28
  • @CladClad It only works with *literals* though, which limits their use to splitting long strings across multiple lines. I've never, personally, used this (or their C-counterparts) for anything else. – trojanfoe Jan 22 '14 at 14:29
  • Yeah but still pretty good to know, I have never seen it anywhere before :s Both ways are good to know actually ;) – Clad Clad Jan 22 '14 at 14:30
  • 3
    +1 I find this syntax is very nice for long SQL statements where I want to break it up on multiple lines to make it more readable. I don't use the literal on the subsequent portions of the string, though, e.g. I always do something like `NSString *str = @"Hey" "Jude" "Don't";` (with only one string literal `@`). I'm not sure if there's a compelling argument one way or the other. – Rob Jan 22 '14 at 15:24
0

I don't know how to do this with macros.

You can do it in Objective C like:

Implement a method like:

- (NSString *)concateStrings:(NSString *)firstArg, ...
{
    NSMutableString *concatString = [[NSMutableString alloc] init];
    va_list args;
    va_start(args, firstArg);
    for (NSString *arg = firstArg; arg != nil; arg = va_arg(args, NSString*))
    {
        [concatString appendString:arg];
    }
    va_end(args);

    return concatString;
}

You can call this method like:

NSLog(@"%@",[self concateStrings:@"hey",@"Jude",@"Don't",nil]) ;

Output:

heyJudeDon't

Make sure that you pass nil at the end.

Midhun MP
  • 103,496
  • 31
  • 153
  • 200