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?
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 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 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).
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...
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 dspeyer on Wednesday August 05, 2009 @01:02AM
(#742886)
> Passing MyArray[x+3] as a macro argument would lexically copy this expression in multiple locations in the macro expansion, causing the generated code to needlessly evaluate *(Myarray+x+3) again and again and again.
Wouldn't any decent optimizing compiler eliminate those common subexpressions? That's one of the basics, isn't it?
Of course, if you're in a tight enough loop to worry about that, check the assembly by hand.
Re:Tips on writing C macros
by ori_b on Tuesday August 04, 2009 @11:30PM
(#742787)
Use inline functions instead of macros whenever possible. They don't have all the tricky gotchas, and they generally have no performance impact over macros.
Re:Tips on writing C macros
by neilc on Tuesday August 04, 2009 @11:55PM
(#742813)
That is silly; there are plenty of situations in which macros are useful in C. I'd be inclined to avoid complex multi-line macros that multiply-evaluate their arguments unless there's a compelling need for them, however.
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:
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". :-)
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.
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.
"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)."
As an example:
----- 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).#define ADD_ONE(a) ({ a + 1; })
x = ADD_ONE(2);
Wouldn't any decent optimizing compiler eliminate those common subexpressions? That's one of the basics, isn't it?
Of course, if you're in a tight enough loop to worry about that, check the assembly by hand.
http://sourceware.org/gdb/current/onlinedocs/gdb_11.html
Tip 2, see tip 1