Friday, May 1, 2009

On the vile nature of C/C++ macros

Let's say you're using MFC. This means you're writing code assuming the presence of Windows headers.

Now let's say you want to get the current time. That's CTime::GetCurrentTime().

Except that there is no GetCurrentTime member of CTime. Why? Because the Windows headers have this line:

#define GetCurrentTime() GetTickCount()

GetTickCount() is a Windows API function that behaves more or less the same as timeGetTime(), which returns a 32-bit unsigned integer representing the number of milliseconds since the system booted up. (Or since said unsigned integer last overflowed; This integer is the basis behind the 49.5 day "inevitable" crash /. used to crow about. Only causes problems when programmers who call it don't understand what it does, or don't care if their program when the 49.5 day mark comes around.)

The net result is that since the Windows headers use a #define to define GetCurrentTime() as GetTickCount(), any code on Windows that might want to use the string GetCurrentTime() as part of a function name gets its function not-so-helpfully renamed to GetTickCount().

I haven't looked, but I rather expect that the MFC runtime DLL exports a function named CTime::GetTickCount that's wholly unrelated to the Windows API call of similar name.

BTW, you run into the same problem if you want to have a function named LoadImage; There's a define that renames it to LoadImageA or LoadImageW, depending on whether you're using MBCS or Unicode.

No comments:

Post a Comment