C Macro Tips and Tricks
mikeash.com
mikeash.com
Traceback (most recent call last): File "index.cgi", line 509, in <module> main() File "index.cgi", line 499, in main if 'iPhone' in os.environ['HTTP_USER_AGENT']: File "/home/mikeash/lib/python2.6/UserDict.py", line 22, in __getitem__ raise KeyError(key) KeyError: 'HTTP_USER_AGENT'
""" It's a little-known feature of C that if you put two string literals next to each other in the source code, they get concatenated:
char *helloworld = "hello, " "world!";
"""That's a good tip that actually works in other languages too. It helps in Python, for example, when creating long strings. Wrapping parentheses around the string and using the quote-continuation rule makes it nice and easy to read.
For example:
foo = ('hello world this is '
'a long string')
is better than: foo = 'hello world this is ' + \
'a long string'
...for two reasons. It avoids string concatenation (the "+" operator) and it avoids the backslash.The C preprocessor is powerful, but brittle. If Scheme's macros are hygienic, C's are pathogenic, so be judicious.
(However, that technique with blocks looks like a good solution to the "many statement expression in macro expression" problem, would that work with C++0x lambdas?)
template <typename T> T max(T a, T b) { return (a > b) ? a : b; }
int max_ints(int a, int b) { return max(a, b); }
Of course this only works if "a" and "b" have the same type. 0x provides a solution for the situation where they don't:
template <typename Ta, typename Tb> auto max(Ta a, Tb b) -> decltype((a > b) ? a : b) { return (a > b) ? a : b; }
int max_int_char(int a, char b) { return max(a, b); }
For example:
#define SOMEMACRO(x) do { \
int y=0; \
for(int i=0; i<x; i++) \
y=dosomething(y, i); \
} while (0)
Which, of course, works fine if you call it as a statement. But it doesn't work if you want to somehow "return" the value of "y" from that: there's no way to embed that kind of loop into an expression.He showed an example of using Apple's Blocks to solve that, can you do the same with C++0x lambdas?
... but you probably shouldn't: don't use a macro where a function will suffice, and if you need to use a macro, write a macro that syntactically wraps around a function if possible. C++, especially 0x, provides a lot of metaprogramming functionality you can use to avoid writing macros in many cases. Using this functionality will give the compiler more information about your program for analysis purposes, which means the compiler can help ensure correctness and better efficiency.