views:

58

answers:

3

I want to make a macro which will inject some code, like:

if (foo) {
[Bar fooBar];
}

and then, where ever I need that, I put FOOBAR in the code. Not sure, but at compile time then the compiler replaces this with the actual code like in the example above. Maybe there's something different than a macro I could use for this?

+1  A: 

I would suggest using something like TextExpander to insert standard chunks of text rather than use Macros.

Alternatively, if you are repeating multiple lines of the same code, why not extract that into a function, and then all you have to do is call the function.

Abizern
+1  A: 

You can define a macro on multiple lines by adding a \ to the end of each line except the last. Unfortunately the macro will expand to a single line when you actually use it.

Mark Ransom
I'm making a big assumption here that objective-c macros are the same as plain C macros.
Mark Ransom
Yes, the C preprocessor language is unchanged in Objective-C.
Peter Hosey
+5  A: 

Use \ to escape each line-break you want to be part of the macro.

However, be aware that using macros like this can hide structure if you aren't careful. Taking your example:

if (bar)
 FOOBAR();
else
 do_something_else();

Guess what this expands to. Probably not what you think. Here's what the compiler sees (indentation adjusted):

if (bar)
 if (foo)
  {
   [Bar fooBar];
  }
;
 else
  do_something_else();

Oops! That semicolon is a separate, empty statement. Each if takes only one statement; the first if's statement is the second if, and the second if's statement is the compound statement ({…}), so they have both met their quota, leaving the semicolon out.

So the semicolon is not bound to an if—it's unconditional. That causes a syntax error when you then try to apply the else to an unconditional statement.

The fix, ugly as it is, is to wrap the contents of FOOBAR in a do…while statement:

#define FOOBAR()       \
 do {                \
  if (foo)         \
   [Bar fooBar]; \
 } while(0) /*semicolon omitted*/

Because we leave out the semicolon in the macro definition, the do…while is an unterminated statement, so that the semicolon outside the macro usage will bind to it. Then our expanded code looks like this:

//First, the unexpanded code again
if (bar)
 FOOBAR();
else
 do_something_else();

//Expanded
if (bar)
 do
  {
   if (foo)
    [Bar fooBar];
  }
 while(0);
else
 do_something_else();

The else now binds to if (bar), as you intended.

Peter Hosey