The Artima Developer Community
Sponsored Link

The C++ Source
Reducing Preprocessor Namespace Pollution
by Bjorn Karlsson and Matthew Wilson
November 6, 2004

<<  Page 3 of 3

Advertisement

Debuggability

There's another advantage to using the inline functions. Sometimes the mappings can involve more than just a name=>name translation, perhaps involving a little tertiary operator (the conditional operator, ?:) play just for extra confusion, as in the following macro/function:
 int ProcessOddNums(int n);
 int ProcessEvenNums(int n);
 
 #ifdef __cplusplus
 inline int ProcessNums(int n)
 {
   return (n % 2) ? ProcessOddNums(n) :
 ProcessEvenNums(n);
 }
 #else /* ?__cplusplus */
 # define ProcessNums(n)     ((n % 2) ? ProcessOddNums(n)
 : ProcessEvenNums(n))
 #endif /* __cplusplus */
By defining the C++ form as an inline, we not only avoid stepping on any other ProcessNums symbol, we can also step into the ProcessNums() function, and avoid the often irritating/confusing mental disconnect one experiences when thinking one is about to step into one function, and ends up in another, leading to time-wasting existentialist digressions — how did I get here? It also significantly eases the business of fine-grained placement of breakpoints, and gives us a stack frame in which to play around and look at function parameters before diving down into the worker functions. This fact alone has proven its worth many times over in our use of the technique.

What About the DRY SPOT?

The solution we've presented addresses the problems associated with macro recklessness, and in practice seems to cause very few problems. However, it does violate the DRY — "Don't Repeat Yourself" [8] — rule (also known as the SPOT — "Single Point Of Truth" [9] — rule), since the mapping from one to the other for a given character encoding is defined in two places. It is possible, either through carelessness or incomplete post-maintenance testing, to end up with different definitions for TheFunc in C and C++. As you can imagine, such bugs are extremely hard to find.

The alternative is to make a single point of definition, based on "safe(r) macros", and then define the user- facing macros/functions in terms of those macros, hence:

 # ifdef ACMELIB_MULTI_THREADING
 #  define ACMELIB_TheFunc     TheFuncMT
 # else /* ? ACMELIB_MULTI_THREADING */
 #  define ACMELIB_TheFunc     TheFuncST
 # endif /* ACMELIB_MULTI_THREADING */
 
 /* The actual mappings for C / C++ */
 #ifdef __cplusplus
 inline void TheFunc() { ACMELIB_TheFunc(); }
 #else /* ? __cplusplus */
 # define TheFunc      ACMELIB_TheFuncMT
 #endif /* __cplusplus */

There's a modest increase in code size and effort, but it's a manifest gain in robustness, and a final cherry on the maintainability cake.

Conclusion

We've illustrated the pervasive problem of namespace pollution caused by preprocessor discriminated function and type definitions, and demonstrated a simple mechanism for making such discriminated symbols play the game the C++ way. This mechanism involves the definition and use of actual functions in C++, which can be linked, can have their addresses taken, and be stepped into, and which are dutiful citizens in obeying C++'s namespace laws.

The cost is a slight increase in admittedly arcane- looking code, but such things are readily amenable to being auto-generated by script. You can also choose to define them in a separate file that is #include'd into your main, handwritten, header file, so you keep your main header nice and neat and comprehensible to users of your code.

Using this technique, you can avoid a host of troubles for yourself and, more importantly, for the users of your code. Now, if only we can get the large software companies to play ball´┐Ż

Thank you for reading,

Bjorn Karlsson and Matthew Wilson

http://www.bigboyandrunningbear.com/

Acknowledgements

Many thanks to Andrei Alexandrescu, James O. Coplien and Walter Bright for casting their esteemed eyes over our drivel.

References

  1. Imperfect C++, Matthew Wilson, Addison-Wesley, 2004
  2. The C++ Programming Language, Special Edition, Bjarne Stroustrup, Addison-Wesley, 2000
  3. The Design and Evolution of C++, Bjarne Stroustrup, Addison-Wesley, 1994
  4. The C++ Style Sweet Spot, A Conversation with Bjarne Stroustrup, Bill Venners, Artima, October 2003
  5. Exceptional C++ Style, Herb Sutter, Addison-Wesley, 2004
  6. recls is one of the exemplar libraries for Matthew's Positive Integration column for C/C++ User's Journal. The column is concerned with integrating different languages with C and C++, and uses different libraries to highlight the issues involved.
  7. http://www.research.att.com/~bs/bs_faq2.html#macro
  8. The Pragmatic Programmer, Dave Hunt and Andy Thomas, Addison-Wesley, 2000
  9. The Art of UNIX Programming, Eric Raymond, Addison- Wesley, 2003

About the Authors

Matthew Wilson is a software development consultant for Synesis Software, and creator of the STLSoft libraries. He is author of the Imperfect C++ (Addison-Wesley, 2004), and is currently working on his next two books, one of which is not about C++. Matthew can be contacted via http://imperfectcplusplus.com/.

Bjorn Karlsson is proud to be a C++ designer, programmer, teacher, preacher, and student. He has finally learned enough about C++ to realize how little he knows. When not reading or writing articles, books, or code, he has the privilege to be a part of the Boost community, and a member of The C++ Source Advisory Board. His book, Beyond The C++ Standard Library: An Introduction to Boost, will be published by Addison-Wesley in 2005. He appreciates it when people send him interesting emails at bjorn.karlsson@readsoft.com.

<<  Page 3 of 3


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us