I’m working with some C code that is quite well-written but makes a lot of use of some fairly complicated #define
macros. Macros are discouraged by the coding guidelines, but they are a necessary evil here. They could’ve been functions except for the fact that they allocate memory on the stack using alloca
and a function would destroy the memory when it exited. Writing these functions as #define
macros keeps everything in the caller’s stack frame so the allocated memory remains valid.
The only problem is that #define
macros are a pain in the butt to write and debug. You have to backslash every line (which looks like a mess) and if you forget you get weird errors. You also have to be careful about putting things in scopes and/or giving them funky names to avoid namespace issues. When you do something wrong, you get really weird errors that point you at the calling code instead of the macro itself (because #define
macros essentially are a string replacement).
Too bad we’re not using C++. C++ smart pointers would obviate the need for alloca
, which in turn would obviate the need for the macros.
Macros aren’t all that bad. I can use them, and still respect them in the morning. They are a special-case sort of tool, though, not useful in many situations. As I’ve written a lot of low-level code, macros are a predictable, fundimental technique. There are things that are only possible with macros, and places where nothing else is as succinct.
C++ templates are almost as bad as macros, at least in terms of debugging and unpredictable side-effects in various compilers. It doesn’t make them any less useful, but certainly limits the number of people who can use them effectively. Templates have their place, though I don’t often see cases for writing new templates (but what would we do without the STL?!).
In the end, I fear code standards that recommend against any valid part of the C or C++ standards. They’re just tools, each useful when used appropriately. I’ve been part of writing standards that suggested avoiding parts of the language, and found they only prevented inexperienced people from learning better ways of doing things (or prevented people who knew the tools from being effective). Embrace and the learn the extent of your tools!
Well said, Bruce.
I agree. I wasn’t suggesting banning #define macros – the title was just a reflection of my momentary frustration with them. I’m definitely not crazy about the fact that I have to backslash everything or that we’re using extensions that make them non-portable or that they are frustrating to debug because the line numbers from gdb and valgrind are totally off or that gcov doesn’t measure code coverage on them, but they are pretty much necessary for this project. Unless we write our own preprocessor or something.
In fact, there is a lot here that I probably would’ve tried to do with templates, if not for the fact that we are restricted from using C++; pure C only.
I’ve since fixed all the problems I was having, though it took longer than it should have, so I’m feeling a bit better about #define macros, but certainly open to alternatives if any came along or were pointed out to me.
So I guess I’d say that I agree that it’s good to learn the extent of your tools, but I’d add that it’s also good to always be on the lookout for better tools (and don’t be afraid to build your own if it’s warranted and won’t impact your commitments).