Variadic macros tricks

Have you ever wanted to write a “for each” loop over all the args of a variadic macro? Or have you ever wanted to overload a macro on the number of arguments? (If you’re saying to yourself, “good grief, why?” — I’ll describe a use case at the bottom of this post.)

I learned how to do this today, and I wanted to blog about it to cement the technique in my own mind. (And I hereby put all the code I show here into the public domain.)

What happened when I decided to learn this technique. I’m trying to spare you… :-) Image credit: xkcd.com

Simple variadic macros

The first piece of magic you need to do something like this is __VA_ARGS__. This allows you to write macros that take an arbitrary number of arguments, using ... to represent the macro’s parameters:


#define eprintf(fmt, …) \
fprintf(stderr, fmt, __VA_ARGS__)

Nice. __VA_ARGS__ is a standard feature of C99, and I’ve known about it for a long time. I’ve also known about GCC (and Clang’s) extension, which attaches special meaning to ##__VA_ARGS__ if it’s preceded by a comma–it removes the comma if ##__VA_ARGS__ expands to nothing. If I change my macro definition to:


#define eprintf(fmt, …) \
fprintf(stderr, fmt, ##__VA_ARGS__)

view raw

fancier-eprintf

hosted with ❤ by GitHub

…I can now call eprintf("hello, world"); without a complaint from the compiler.

But it’s not enough

That doesn’t let me do a “for each” loop, though. All the args that I pass are expanded, but I can’t do anything with them, individually. I have no names for my macro’s parameters–just the anonymous .

I went poking around, not expecting to find a solution, but I was pleasantly surprised.

Continue reading

How Enums Spread Disease — And How To Cure It

Poorly handled enums can infect code with fragility and tight coupling like a digital Typhoid Mary.

Say you’re writing software that optimizes traffic flow patterns, and you need to model different vehicle types. So you code up something like this:

vehicle_type.h

enum VehicleType {
    eVTCar,
    eVTMotorcycle,
    eVTTruck,
    eVTSemi,
};

Then you press your enum into service:

route.cpp

if (vehicle.vt == eVTSemi || vehicle.vt == eVTTruck) {
    // These vehicle types sometimes have unusual weight, so we 
    // have to test whether they can use old bridges...
    if (vehicle.getWeight() > bridge.getMaxWeight()) {

Quickly your enum becomes handy in lots of other places as well:

if (vehicle.vt == eVTMotorcycle) {
    // vehicle is particularly sensitive to slippery roads

And…

switch (vehicle.vt) {
case eVTTruck:
case eVTSemi:
    // can't use high-occupancy/fuel-efficient lane
case eVTMotorcycle:
    // can always use high-occupancy/fuel-efficient lane
default:
    // can only use lane during off-peak hours
}

Diagnosis

The infection from your enum is already coursing through the bloodstream at this point. Do you recognize the warning signs?

  • Knowledge about the semantics of each member of the enum are spread throughout the code.
  • The members of the enum are incomplete. How will we account for cranes and bulldozers and tractors and vans?
  • Semantics are unsatisfying. We’re saying cars are never gas guzzlers or gas savers; what about massive old steel-framed jalopies and tiny new hybrids?

A vehicle that challenges our tidy enum. Photo credit: Manila Imperial Motor Sales (Flickr)

The infection amplifies when we want to represent the enum in a config file or a UI. Now we need to Continue reading