views:

548

answers:

3

I'm trying to get a better understanding of what place (if any) Macros have in modern C++ and Visual C++, also with reference to Windows programming libraries: What problem (if any) do Macros solve in these situations that cannot be solved without using them?

I remember reading about Google Chrome's use of WTL for Macros (amonst other things) from this blog post, and they are also used in MFC - here is an example of a Macro from that blog post I'd like explained in a superb amount of detail if possible:

// CWindowImpl
BEGIN_MSG_MAP(Edit)
  MSG_WM_CHAR(OnChar)
  MSG_WM_CONTEXTMENU(OnContextMenu)
  MSG_WM_COPY(OnCopy)
  MSG_WM_CUT(OnCut)
  MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition)
  MSG_WM_KEYDOWN(OnKeyDown)
  MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
  MSG_WM_LBUTTONDOWN(OnLButtonDown)
  MSG_WM_LBUTTONUP(OnLButtonUp)
  MSG_WM_MBUTTONDOWN(OnNonLButtonDown)
  MSG_WM_MOUSEMOVE(OnMouseMove)
  MSG_WM_MOUSELEAVE(OnMouseLeave)
  MSG_WM_NCCALCSIZE(OnNCCalcSize)
  MSG_WM_NCPAINT(OnNCPaint)
  MSG_WM_RBUTTONDOWN(OnNonLButtonDown)
  MSG_WM_PASTE(OnPaste)
  MSG_WM_SYSCHAR(OnSysChar)  // WM_SYSxxx == WM_xxx with ALT down
  MSG_WM_SYSKEYDOWN(OnKeyDown)
END_MSG_MAP()

I've read these articles to do with Macros on MSDN but am trying to also pick up best practices for writing or avoiding Macros and where/when to use them.

+3  A: 

All of those Macros are defined in public sdk header files, so you can go read what they do yourself if you want. Basically what is happening here is you're generating a WndProc function using Macros. Each MSG_WM_* entry is a case statement that handles the given window message by translating its arguments from wParam and lParam into their original types and calling a helper function (which you then get to go implement) that takes those types as arguments (if appropriate—some window messages have 0 or 1 arguments).

In my opinion all this is crap. You're trading off having to write a bunch of boiler-plate up front but in exchange you make it much harder to debug later. Macros don't have much of a place in my modern programming world, other than to check if they are defined or not. Macros that do flow control, or assume specific local variables are always defined, etc, make me quite unhappy. Especially when I have to debug them.

jeffamaphone
Thanks: I'm hearing that Macros should be avoided (that was my suspicion) in modern C++ and I definitely agree. I'd still like to understand what's happening for reading legacy code - is there a link you can recommend for viewing the public SDK header files?
Peter McGrattan
Macros for boiler plate code like window procedures are actually a real godsend. It is the kind of code that is just repeated over and over and never needs to be changed. The best solution would involve a DSL for window procedures but in the lack of this, these are good
1800 INFORMATION
Saving typing is good, but there are subtleties to this. For example, its not obvious when you should call the base class implementation, or to novices even how to call it. These sorts of overly complex macros lead to hard-to-find bugs. There is a time and place, I grant that.
jeffamaphone
jeffamaphone
@jeffmaphone: The same subtleties arise if you are writing plain old Win32 - you always need to know when you should call the DefWndProc and what the various parameters mean and so on. Once you have a good handle on that then the macros will make your code much cleaner and reduce the chance of error
1800 INFORMATION
+1  A: 

(The question is kind of fragmented, but ignoring the Windows part):

X-Macros use the preprocessor to avoid code duplication.

Matt Curtis
Thanks: An interesting read although the article is from 2001 and talks about tricks used by assembly language programmers in the 60's. Are the X Macro patterns outlined in the article still relevant for use in C++ in 2009, are they recommended?
Peter McGrattan
Because C++ hasn't grown a real metalanguage since 2001, I'd say the techniques are still very relevant. They are in regular use in my workplace, to keep code clean and maintainable. They're one of the few sane ways of automatically generating code entirely within C++.
Matt Curtis
By the way as Charlie Martin says, this technique isn't necessarily nice, but it's all relative - IMHO it's the nicest way to solve some problems in C++, that would be solved far better if it had a better metalanguage. (C++ really is 3 syntaxes-in-1: everyday code, templates, and the preprocessor.)
Matt Curtis
+3  A: 

Peter, you might as well ask if vi or EMACS is the better editor. (EMACS, by the way.) There are a lot of people who think the C preprocessor is a horrible idea; Stroustrup and Jim Gosling among them. That's why Java has no preprocessor, and there are innumerable things Stroustrup put into C++, from const to templates, to avoid using the preprocessor.

There are other people who find it convenient to be able to add a new language, as in that code.

If you read the original Bourne shell code, you'll find it looks like

IF a == b THEN
   do_something();
   do_more();
ELSE
   do_less();
FI

Steve Bourne basically used macros to give it an Algol68-like look (that being the Really Cool Language then.) It could be very difficult to work with for anyone but Steve Bourne.

Then have a look at the Obfuscated C contest, where some of the most amazing obfuscations take advantage of the #define.

Personally, I don't mind too much, although that example is a little daunting (how do you debug that?) But doing that kind of thing is working without a net; there aren't many Wallendas out there.

Charlie Martin
Thanks: a language within a language is a good way to think. Do you have any examples of 'good' Macros or Macros you've used that you 'don't mind too much'?
Peter McGrattan
I can't think of any uses of complicated macros that I really *liked*. Sometimes, like in the macros in the Linux kernel, there's a reason for them (an inner loop in the kernel gets hit a *lot*); sometimes they implement a DSL, like the example above.
Charlie Martin
Probably the most complex macros I've ever *liked* were logging macros, implementing something like log4j for C.
Charlie Martin