News for hackers. Stuff that matters.
Re:Tips on writing C macros by paulbaumgart on Tuesday August 04, 2009 @08:29PM (#742516)
What's that nonsense with the do-while loop? Why not just enclose the macro body in both curly braces and then in parentheses?

Also, more useful (GCC only, though) than just enclosing parameters in parentheses, because it makes macros side-effect safe: http://en.wikipedia.org/wiki/C_preprocessor#Multiple_evaluat... Of course, in the macro in the article, the first 2 parameters need to be modifiable lvals anyway, so for those the whole deal with parentheses and the typeof construct is a moot point.

I'd write the proposed macro as:

  #define MYMACRO(a,b,c) \
    ({ \
      typeof (c) _c = (c); \
      a = b + _c; \
      b = _c * 2; \
    })
Re:Tips on writing C macros by gchpaco on Tuesday August 04, 2009 @09:11PM (#742592)
Curly braces and then parens is a GCC extension. If you're going to do complicated macrology, GCC is the way to go because of typeof and a bunch of related extensions designed to make macro use work. But it's still a staggering amount of effort and not worth it in the long run.
Re:Tips on writing C macros by tb on Tuesday August 04, 2009 @09:04PM (#742578)
The do-while "nonsense" is a pretty standard construct, so much so that I'd never seen your approach - which I admit looks nicer. How well is that supported across different compilers? Is it part of C99, for example?
Re:Tips on writing C macros by paulbaumgart on Tuesday August 04, 2009 @09:19PM (#742603)
No, it's not in C99: http://www.redhatrenewals.com/docs/manuals/enterprise/RHEL-4...

Admittedly I have little experience with compilers other than GCC, but all things considered, I'd shy away from using anything but really basic macros without the compound-statement-in-parens and typeof() extensions that GCC provides.

Perhaps I spoke too harshly, calling it "nonsense". :-)

Re:Tips on writing C macros by paulbaumgart on Thursday September 03, 2009 @07:09PM (#803805)
So, just to follow up, I saw that the OCUnit macros ( http://www.sente.ch/software/ocunit/ ) are all using defined using the do...while(0) guard.

I was wrong. It's the more platform independent way to do things.

For code that's only ever going to be compiled with GCC, though, the statement expression method is cleaner, I think.

Re:Tips on writing C macros by tedunangst on Tuesday August 04, 2009 @09:20PM (#742605)
It's only supported by gcc and some edg based compilers. edg has trouble with it in some c++ code. Just think of how adding this complicates your grammar.
Re:Tips on writing C macros by michaelfairley on Tuesday August 04, 2009 @09:03PM (#742575)
With your code, placing a semicolon after the macro leads to a compile error. Semicolons are not valid after arbitrary blocks, but it is acceptable to place them after do-while loops.

It's much nicer to be able to call "MYMACRO(1, 2, 3);" than it is to have to remember to leave the semi-colon off.

Re:Tips on writing C macros by paulbaumgart on Tuesday August 04, 2009 @09:21PM (#742607)
It compiles fine on GCC. For other compilers, the Wikipedia page I linked offers the caveat:

"This construct is not legal ANSI C; both the typeof keyword, and the construct of placing a compound statement within parentheses, are non-standard extensions implemented in the popular GNU C compiler (GCC)."

Re:Tips on writing C macros by greyboy on Tuesday August 04, 2009 @08:48PM (#742551)
Excuse my lack of C knowledge, but using your proposed macro, what would be the result of calling:

  MYMACRO(x,y,x+y)
with your inclusion of typeof()?
Re:Tips on writing C macros by paulbaumgart on Tuesday August 04, 2009 @08:52PM (#742559)
typeof is pretty smart. Since in C all types are known at compile-time, the compiler can put in there in whatever type typeof's parameter resolves to- even if it's an expression.

As an example:

  int main () {
    typeof (1.0f + 10) a;
    int * b = &a;
  }
-----

  $ g++ test.c
  test.c: In function ‘int main()’:
  test.c:3: error: cannot convert ‘float*’ to ‘int*’ in initialization
I'm using g++ because it actually spits out type information for incompatible pointers- probably something having to do with it being an error in C++ but valid in C (with a warning, at least in GCC).
[deleted]
Re:Tips on writing C macros by paulbaumgart on Tuesday August 04, 2009 @08:44PM (#742543)
Same with what I suggested:

  #include <stdio.h>

  #define MYMACRO(a,b,c) \
    ({ \
      typeof (c) _c = (c); \
      a = b + _c; \
      b = _c * 2; \
    })

  int main() {

    int a = 0, b = 0;

    if (1)
      MYMACRO(a,b,1);
    else
      MYMACRO(a,b,2);

    printf("%d, %d\n", a, b);
  }
-----

  $ gcc -o test test.c
  $ ./test
  1, 2
Edit: Just for context: this was responding to a post pointing out that the do-while construct allows you to use a semi-colon after the macro invocation.
Re:Tips on writing C macros by doug11235 on Tuesday August 04, 2009 @08:49PM (#742553)
And another feature I like about ({ }) macros (anyone know the proper name here?) is you can return values. Clearly more useful in an example a bit more complex but...

#define ADD_ONE(a) ({ a + 1; })

x = ADD_ONE(2);

Re:Tips on writing C macros by tedunangst on Tuesday August 04, 2009 @09:15PM (#742599)
They are called statement expressions.
Re:Tips on writing C macros by sketerpot on Wednesday August 05, 2009 @01:52AM (#742921)
What if you already have a variable called _c and you pass it to MYMACRO? Is there any way of generating a guaranteed-unique symbol, similar to GENSYM in lisp?
Re:Tips on writing C macros by abecedarius on Tuesday August 04, 2009 @09:14PM (#742596)
This ({ ... }) syntax was not in the original ANSI C or K&R. Is it in C99 or in GNU C only? I've only ever seen it in GNU C.