#define square(x) (x*x) ... i = 10; square(i++); // did you really want (i++*i++) // what is the value of i now? // below version is better, but does not help the i++ #define square(x) ((x)*(x))Always parenthesize the parameters that macro gets, it will help at least some of the problems.
Pre-Defined macros All C++ define the following macros
__DATE__ //a literal containing the compilation date in the form "Apr 13 1998" __TIME__ //a literal containing the compilation time in the form "10:01:07" __FILE__ //a literal containing the name of the source file being compiled __LINE__ //a decimal integer containing the current line number in the source file _MSC_VER //compiler version in Microsoft world, 1200 for Visual C++ 6.0 or later _M_IX86 //defined for x86 processors. _DEBUG // Debug mode NDEBUG // not-debugging, WIN32_RELEASE mode
File Guards Good for header files, defining namespaces
#ifndef filename_h #define filename_h #endif // filename_h === #ifndef namespace #define namespace #endif // namespace
assert Assert disappears when you are in RELEASE mode, so there is no overhead in the production mode.
You can also do things like:
// better error message with explanation assert(x < 10 && "x is not less than 10"); // avoid assert(0), try an informative message for a change assert( !"Unreachable code in xxxx");Whether you should write your own version of assert or not is open to debate. Here is a nice pattern if you chose to have your own assert.
// At the top of every file define a new MACRO
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// deine your own ASSERT in a header file as follows
#ifdef _DEBUG
#define ASSERT(f) \
do \
{ \
if (!(f) && AssertFailedLine(THIS_FILE, __LINE__)) \
CustomDebugBreak(); \
} while (0) \
#else
#define ASSERT(f)
#endif
// Lots of ways to define AssertFailedLine and CustomDebugBreak
// just watch out for asserts inside asserts
// _M_IX86Defined for x86 processors.
// DebugBreak is a Win32 function
#if defined(_M_IX86)
#define CustomDebugBreak() _asm { int 3 }
#else
#define CustomDebugBreak() DebugBreak()
#endif
// AssertFailedLine can put up a window asking the user to stop or continue
// Watch out, you might be stretching the intentions of assert
// You may not be in a graphical environment
// Your assertion may have failed because you are out of memory, trying
// to open a window is not going to help things
// You can also use ASSERT-like macros to trace your program in debug mode
// Define a function Trace
void Trace(char* frm, ...)
{
va_list args;
va_start(args, frm);
vprintf(frm, args);
va_end(args);
}
// A macro to call this function if needed
#ifdef _DEBUG
#define TRACE Trace
#else
#define TRACE
#endif
// An use trace in the code
TRACE("Current values, x: %i y: %i \n", x, y);
The Boost library has lots of goodies, even if you decide not to use
the library, it is worth checking it out for examples. If you wanted
to use assert from Boost you would do:
// include the assertion library and enable handler // if you do not enable handler, BOOST_ASSERT is the same as assert #define BOOST_ENABLE_ASSERT_HANDLER #include// You need to define your handler void boost::assertion_failed(char const * expr, char const * function, char const * file, long line) { ... } // use BOOST_ASSERT just like normal assert BOOST_ASSERT(x == y);
Not for variables Do not use macros to 'define' variables. Use 'const int' instead. The compiler will be able to generate better error messages and using macros does not make your code any cleaner in the case of variables.
IFDEFINED_XXX I hate #ifdef statements in code, but I understand that it might be unavoidable at times. Each macro you write also makes your code harder to read. I am undecided about the macro below.
#ifdef FOO
#define IFDEFINED_FOO(arg) { arg }
#else
#define IFDEFINED_FOO(arg)
#endif
...
// only execute if FOO is defined
IFDEFINED_FOO
(
cout << "Hello Foo\n";
cout << "yes, mumble\n";
x++;
);
OK, so it uses parenthesis '(' instead of the nice curly-prackets '{}'
after IFDEFINED_FOO and FOO better be something reasonable like INTEL_SIMD,
JOYSTICK_SUPPORT, or something like that. Maybe it is the Lisp hacker
in me that likes the parentheses, but I find this easier to read than
#ifdef statement;
pragma It seems to be used much more with MSVC than others. The push/pop
// Specifies that the file will be included (opened) only once by the // compiler in a build. // This should be in addition to #ifdef fule guards. Not all compilers speak pragmas #pragma once // change some default warnings #ifdef FOO_BAR # pragma warning(push) # pragma warning(disable: 4511) // copy constructor could not be generated # pragma warning(disable: 4512) // assignment operator could not be generated #endif ... code #ifdef FOO_BAR // pop restores the state of all warnings to what it was at the beginning of the code. # pragma warning(pop) #endif // display warning 4385 just once, sick of hearing it #pragma warning( once : 4385 ) // pragma can also output text at compilation time #pragma message( "Compiling " __FILE__ ) #pragma message( "Last modified on " __TIMESTAMP__ )