- portability
- generate strings from identifiers
- Insert file and line of the call location (or other context) automatically when calling a function.
- X-macros
- Scopes with exit statement given at beginning, hacked using "for" statement and a condition that evaluates to true only the first time. A little bit brittle when the exit statement must not be skipped (goto, return).
I'm sure there are more, but I'm too tired to think harder... Here is an example of the last category:
#define TIMED_SECTION_(name, t) FOR_SCOPE(Timer t = start_timer(); print_passed_time(name, t))
#define TIMED_SECTION(name) TIMED_SECTION_(name, UNIQUE_NAME())
Not giving the FOR_SCOPE() and UNIQUE_NAME() macros here for brevity. They add another 3-5 reusable lines. Use like this: TIMED_SECTION("foo the bar")
{
/* Do stuff, time spent in this scope will be measured and printed on scope exit. */
}
Other more advanced languages can do some of the same things, sometimes more robustly, or not at all (X-macros is probably hard to replace for languages that are not LISP). But it typically comes at a cost in complexity, hard to use type systems, complicated semantics with edge cases... And they only allow you to do what is already built into the language!