views:

94

answers:

5

I'm trying to instrument some code to catch and print error messages. Currently I'm using a macro somethng like this:

#define my_function(x) \
  switch(function(x)) { \
    case ERROR: \
      fprintf(stderr, "Error!\n"); \
      break; \
  }

Normally, I never capture the function output and this works fine. But I've found a couple cases where I also need the return value of function(). I tried something like the following, but this produces a syntax error.

#define my_function(x) \
  do { \
    int __err = function(x); \
    switch(__err) { \
      case ERROR: \
        fprintf(stderr, "Error!\n"); \
        break; \
    } \
    __err; \
  } while(0)

I could declare a global variable to hold the return value of the function, but that looks ugly and my program is multithreaded, so that's likely to cause problems. I'm hoping there's a better solution out there.

Thanks!

+5  A: 

This is relatively complicated code, there is not much reason to have it in a macro. Make it inline (C99) or static (C89) or both if you really want to place it in a header file. With any reasonable compiler this then should result in the same efficiency as a macro.

Jens Gustedt
+2  A: 

There are 2 missing \ in your second expression (line 2 and 3), is this correct?

tristopia
Sorry, just typos
Michael Mior
+1 No reason to down vote this answer
Edward Leno
I just downvoted because this doesn't answer the question since the syntax error was unrelated to the typos.
Michael Mior
Now I understand what you wanted to do (the answer of qrdl gave me the hint). Using the macro as a `lvalue`. As the question was written the only syntax error visible was the missing `\`, had you explicitly put the use of the macro, it would have been obvious what you intended. My bad.
tristopia
A: 

A few points:

  • As @William Pursell mentioned, add the missing continuation lines.
  • I don't understand what the __err; by itself is trying to do.
Edward Leno
No, `while (0)` should be `while(0)`
Michael Mior
If I recall, do while doesn't check the condition the first time. (I don't use it much). So it will be run once. Whats the point of the do while, anyway?
mathepic
If while(0) is correct, I agree with @mathepic ... why have it?
Edward Leno
I believe he meant not to have a semicolon in it, so that to use the macro you must use a semicolon.
mathepic
+4  A: 

GCC has a feature called statement expressions

So if define macro like

#define FOO(A) ({int retval; retval = do_something(A); retval;})

that you will be able to use like like

foo = FOO(bar);
qrdl
That's basically what I was trying to do with the above. I think @Jens was right that an inline function better suits my needs.
Michael Mior
A: 

Sorry, this is an edit...

  1. I think you just need the curly braces. No need for the do..while keywords
  2. Make sure that the backslashes are the last characters on each line (no space after).
  3. If you need to get the err value out of the macro, you can just add a parameter

Like so:

 #define my_function(x, out) \
      { \
        int __err = function(x); \
        switch(__err) { \
          case ERROR: \
            fprintf(stderr, "Error!\n"); \
            break; \
        } \
        __err; \
        (*(out)) = _err; \
      }

To preserve the pass-by-reference C paradigm, you should call my_function this way:

int output_err;

my_function(num, &output_err);

This way, later, if you decide to make my_function a real function, you don't need to change the call references.

Btw, qrdl's "Statement Expressions" is also a good way to do it.

hopia