Friday 1 April 2011

When Macros Invade Your Home

It's not very often I'd be inclined to post code bugs that I come across during development, but this one foxed me for sufficient time and the answer was face-palming enough that I thought I'd post it.

This is a little excerpt from some of the GUI handling code.  When you click on a control, it iterates through any sub-controls in a recursive fashion and calls the same function on those:
      virtual int mouseDown(const Tuple2f& Position, const IBaseMouseEvents::mouseStateChange& State ) override
      {
         int Result = -2;
         //Check for intersecting with this control's layout
         if ( Overlaps(Position) )
        {
            //
            Result = -1;
            //Call mouse down on subobjects
            for( uint32 i=0; i<Objects(); i++)
            {
               //Update the final result
               Result = max(Result, Object(i)->mouseDown( Position, State ) );
            }
         }
         return Result;
      }
This seems pretty straightforward, but when I'd added a Next button to the GUI it was oddly getting clicked 8 times every time I pressed it, and I just couldn't work out what was happening for about 20 minutes. 

Worked it out yet?  If so, congratulate yourself on being a smug bastard.

The problem is that the max() function in C++ is defined as a macro, rather than a function, and this macro is (((a) > (b)) ? (a) : (b)).  As a result,the mouseDown() method could get called twice per loop iteration, and as my button control was 3 levels down the GUI hierarchy, this meant 2^3 = 8 clicks rather than 1. 

Bollocks.

Right, now back to programming rather than scratching my head!

No comments:

Post a Comment