Macros first and foremost are typically evaluated at pre-processor time.
Thats to say, in a language like C or C++ before your source code gets built to execute it goes through two distinct phases:
1) Pre-processor phase where macros are expanded and directives are evaluated.
2) The compiler is then free to accept source code in it's full form.
Most macro languages, such as the one used in C or others like m4 are actually more powerful than most understand. m4 is essentially a programming language and is what is considered turning-complete (see:
http://en.wikipedia.org/wiki/Turing-complete).
Macros language are actually quite powerful. The purpose behind them is to "pre-process" some text (source code, HTML, etc) into a more complete form.
They really don't share much in common with a function, as their output is inlined at the point the macro exists (if you are writing code in C/C++ you can optionally choose to force/suggest to the compiler the function should do the same). As it's been said already, they are type-less which is why most people try and avoid them as function equivelants. Instead, you should use functions when a function makes sense and use macros when you find yourself repeating complex statement through out functions.
For example, in Windows development you often need to shift bits around in order to extract only parts of a 32 bit integer that are of interest to you. Developers seen this an wrote a series of Macros, one in particular is HIWORD.
Consider the usefulness of HIWORD when capturing mouse events in an SDK application. When you click the mouse the X,Y coordinates are passed to the message handler via single LONG (32 bit) parameter usually named lParam.
Because the X,Y coordinates are encoded as a single 32 bit integer, getting access to them individually requires some binary shifting/magic, which is cryptic and breaks if Windows ever switched to 64 bit integers.
Using the HIWORD macro you can easily isolate the Hi-order word of the 32 bit integer and get the full Y coordinate seprate from the X.
HIWORD looks like:
Code: Select all
#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF))
Now instead of typing that binary magic everytime you need to isolate the hiword of a 23 bit integer you can use thew above macro like so:
Decimal = Binary
HIWORD(696969696) = 1010 0110 0010 1011
1010 0111 1000 0000
The
bold bits are HIWORD which we are interested and is what HIWORD returns instead of 696969696.
HIWORD(696969696) = 42880 (assuming i've done my math right and haven't f'ed up with byte order)
It's common in C/C++ Windows 32 development to encode any number as a 32 bit integer (for physical reasons) so values such as 32 bit colors are a perfect fit for MACROS because you will often need to isolate the Red, Green, Blue and Alpha components separately from each other. Macros save the day here BIG TIME.
Those are the best examples of when and why you should use macros as pseudo-functions. They are best used to simply otherwise complicated anc cryptic expressions, not substitute functions for the sake of speed (no function call over head).
The C/C++ preprocessor is actually pretty powerful, although not quite turing-complete (to my knowledge) is does offer some other interesting directives, such as conditionals.
This is another excellent reason to use macros. I have to re-iterate the importance of accepting the face that a pre-processor is the first phase of a source compilation. I'll explain why this is important.
One of the handiest macros I have ever used was the coveted ASSERT macro in MFC. It basically allows you to quickly test variables and especially arguments. Similar to unit testing, but instead of testing the interface, your testing the implementation.
Code: Select all
function _processChecks($arg1, $arg2)
{
// NOTE: $arg1 absolutely must be an integer between 10 and 300 otherwise all hell will break loose.
// The following macro would cause an exception if not
ASSERT($arg1 >= 10 && $arg1 <= 300);
}
Here is what makes the above macro so cool. ASSERT is *only* injected into your in a debug version. That means, the additional processing caused by ASSERT doesn't exist in release candidates. It's only part of your source code when you debug, when you release publicaly the code is removed (or rather not expanded into your sourcecode).
So using a Macro, youve' essentially kept your application clean of unnesscary code, whilst still having a simple debugging tool at your disposal. How this is possible, is thanks to the C pre-processor's conditional directives.
During the pre-processor phase, you can define a constant labeled DEBUG and actually test for that label's presence and if it's existant, insert the ASSERT code otherwise expand into a blank so the pre-processed source code doesn't compile the ASSERT code.
Pre-processor's are also responsible for including header files. Remember that in a compiled program, it doesn't matter what source files are used at any given time, unlike PHP which requires a dynamic script loading facility.
In short, macros are powerful things...don't limit yourself by thinking they are simply a pre-processed constants or efficient/inlined functions.