Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Some Handy Visual C++ Pre-Processor Macros

5.00/5 (2 votes)
10 Apr 2012CPOL2 min read 31.9K  
C/C++ pre-processor macros which I have found to be quite useful, so I decided to share them. I hope they help you as much as they've helped me.

Over the last few years, I’ve been writing a lot of C++ that I’ve targeted for multiple platforms and/or multiple compilers. It has always been somewhat of a delicate task to make C++ code portable, especially when starting with Visual Studio and targeting other platforms like Linux using GCC.

Along with multi-target compilations, C++ pre-processor macros can be a useful tool in reducing the amount of mundane, rather simple, and rudimentary code that many C++ programmers find themselves writing. Here’s a few macros that I’ve used to ease my own development pain, I hope someone else can find them as handy as I have.

Please, by all means if I am incorrect somewhere please correct me. Also, if you wish to add to this list, feel free to do so.

Cross-Compilation Helpers

First up, one of the more common tasks, especially when writing libraries versus executable programs, is exporting symbols. The process to export symbols is different for the various compilers. The following should take care of GCC and MSVC:

C++
#if defined(_MSC_VER)
#  define LIB_EXPORT __declspec(dllexport)
#  define LIB_IMPORT __declspec(dllimport)
#elif defined(__GNUC__)
#  define LIB_EXPORT /* */
#  define LIB_IMPORT extern
#endif
#
#if defined(__cplusplus)
#  define EXTERN_C extern "C"
#else
#  define EXTERN_C /* */
#endif

Use the EXTERN_C macro when name-mangling on exported functions must be avoided. 

There are many ways to tackle symbol exports. In fact if I’m not mistaken, GCC now has synonyms for __declspec(dllexport/dllimport) so there may not even be a need to use the pre-processor to first establish which compiler is in use for the import/export macros mentioned above. It all depends on which version of GCC you’re using.

Calling Convention Helpers

Most, if not all compilers assume a calling convention when a function is not decorated with one. When problems arise with mis-matched calling conventions (almost always with exported functions) then use the following macros to specify a calling convention rather than leaving it up to the compiler. 

C++
#if defined(_MSC_VER)
#  define STDCALL __stdcall
#  define CDECL __cdecl
#  define FASTCALL __fastcall
#elif defined(__GNUC__)
#  define STDCALL  __attribute__((stdcall))
#  define CDECL /* */
#  define FASTCALL __attribute__((fastcall))
#endif 

Function Inlining 

Compilers will often attempt to make functions inline where it makes sense to do so (depending on compiler flags, etc.). If you wish to force the compiler to make a function inline, use the following macro: 

C++
#if defined(_MSC_VER)
#  define FORCEINLINE __forceinline
#elif defined(__GNUC__)
#  define FORCEINLINE inline
#endif 

Struct Member Alignment

Another possible area of compatibility mismatch is with member alignment. To force the compiler to use a specific member alignment byte-boundary, use the following macro: 

C++
#if defined(_MSC_VER)
#  define DECL_ALIGN(x) __declspec(align(x))
#elif defined(__GNUC__)
#  define DECL_ALIGN(x) __attribute((aligned(x)))
#endif

Utility Macros

I’ll end this post with some utility macros that I find to be pretty helpful…

Inline-Square 

C++
#if !defined(sqr)
#  define sqr(x) ((x)*(x))
#endif

Min/Max

C++
#if defined(min)
#  undef min
#  define min(a, b)	(((a)<(b))?(a):(b))
#endif
#if defined(max)
#  undef max
#  define max(a,b)	(((a)>(b))?(a):(b))
#endif  

Class Declarations (my personal favorite)

C++
#define DECLARE_CLASS_NOBASE(className) typedef className ThisClass
#define DECLARE_CLASS(className, baseClass) typedef baseClass BaseClass;\
DECLARE_CLASS_NOBASE(className) 

You can get rather creative with the above macro. I use it for a redumentary form of reflection or for logging purposes by converting the class name to a string that can be evaluated at run-time.

Example:

C++
#define DECLARE_CLASS_NOBASE(className) typedef className ThisClass;\
virtual const char * ThisClassName() const { return #className; }
#define DECLARE_CLASS(className, baseClass) typedef baseClass BaseClass;\
virtual const char * BaseClassName() const { return #baseClass; }\
DECLARE_CLASS_NOBASE(className)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)