The C Preprocessor

A quick post on something I just observed about the C preprocessor.

The C preprocessor is an odd beast. I don’t know of any other language in widespread modern use that has an equivalent feature (not counting C++, where it exists but probably shouldn’t be used).

I guess this post will assume a basic knowledge of what the pre-processor is/does, or we’ll be here all day.

The preprocessor is great for defining names for constants without taking up any memory. It’s OK for ensuring once-only inclusion of header files, though I prefer to not have headers include headers in the first place. It’s OK up to a point for conditional inclusion of code, though that quickly gets difficult to manage, especially if your IDE isn’t particularly #define-aware. It is mostly appalling for anything more complex.

Today I came across an interesting quirk of the preprocessor that in hindsight is obvious, but when looking at it, I wondered how it’s done.

Take the following:

#define VERSION 1
#if VERSION == 1
// Do something
#else
// Do something else
#endif

That’s simple enough, right? The preprocessor replaces VERSION with 1, then 1 == 1 is true, so the top “//Do something” gets compiled, and the bottom one doesn’t.

Now take this:

#define VERSION V1
#if VERSION == V1
// Do something
#else
// Do something else
#endif

This works the same, but how? I always thought that the preprocessor ultimately worked on integers. Is it perhaps stringifying the symbols, so “V1” == “V1” is true? Doesn’t seem very likely. Is it clever enough to work out that V1 == V1 is true without any other work (i.e. does it stop trying macro replacement at that point)?

The answer is that the preprocessor can take “Identifiers that are not macros, which are all considered to be the number zero.”

So when the preprocessor replaces the VERSION identifier with V1, it then tries to replace the V1 identifier with something. When it can’t, it replaces it with the numeral 0. Then, 0 == 0 is true!

Moreover, you can actually test for this occurring at compile-time with the -Wundef GCC flag, which will throw a warning on non-macro identifiers in #if statements.

You never really stop learning stuff about C…

Advertisements
This entry was posted in Computing and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s