#define
directive#define
is a
#define identifier replacement-text
Before compilation, the compiler replaces any occurrences of identifier
that don’t occur as part of a replacement-text
.
This allows #define
to create Symbolic Constants and Macros.
#define
to create Symbolic ConstantsSymbolic Constants can store any text as the replacement-text
:
#define PI 3.142
The replacement-text
here is 3.142
, which is a numeric literal.
Another example:
#define PI = 3.142
The replacement-text
here is = 3.142
, which is not a numeric literal.
The following code provides an example of how to use #define
to create Symbolic Constants:
#include <iostream>#define PI_1 3.142#define PI_2 = 3.142using namespace std;int main() {double pi_1 = PI_1;double pi_2 PI_2;cout << "PI_1: " << pi_1 << endl;cout << "PI_2: " << pi_2 << endl;return 0;}
Lines 7 & 8 in the snippet above show how both Symbolic Constants examples can be used. PI_1
is supplying the value 3.142
to pi_1
, whereas PI_2
is supplying = 3.142
to pi_2
, which can be identified by the missing =
in line 8.
On the contrary, C/C++ Constants declared with the const
keyword can only declare type-specific constants:
const double PI = 3.142
The value of the PI
constant is 3.142
, not = 3.142
, as was the case in the second Symbolic Constant example.
The examples above also imply that Symbolic Constants do not apply
#define
to create MacrosMacros also follow the same structure as Symbolic Constants; however, Macros allow arguments to be included in the identifier
:
#define SQUARE_AREA(l) ((l) * (l))
Unlike in functions, the argument here is enclosed in parenthesis in the identifier
and does not have a type associated with it.
Before compilation, the compiler will replace every instance of SQUARE_AREA(l)
by ((l) * (l))
, where l
can be any expression. An example is shown below:
#include <iostream>#define SQUARE_AREA(l) ((l) * (l))using namespace std;int main() {int len = 2;int area = SQUARE_AREA(len);cout << "Area of Sqaure of length 2 is: " << area << endl;return 0;}
Here, the len
variable (with value 2
) is substituted as the value for l
in SQUARE_AREA(l)
; therefore, the expression ((len) * (len))
evaluates to 4
.
Additionally, it is also possible to have multiple arguments in Macros, you simply need to add extra variable names separated by commas:
#define RECTANGLE_AREA(l, w) ((l) * (w))
Lastly, a few traps to be aware of:
In the following snippet, the l
argument is not enclosed in a parenthesis in the replacement-text
:
#define SQAURE_AREA(l) (l * l)
In this case, if an expression is passed as an argument, it would lead to unexpected behavior, as shown below:
#include <iostream>#define SQUARE_AREA(l) (l * l)using namespace std;int main() {int area = SQUARE_AREA(2 + 2);cout << "Area of Sqaure of length 4 is: " << area << endl;return 0;}
The area of a square, with a length of 4
, is 16
. However the result of the above code shows 8
. This is due to operator precedence: when l
is substituted by 2 + 2
, the expression (l * l)
becomes (2 + 2 * 2 + 2)
. Since *
has a higher precedence than +
, the expression simplifies to 2 + 4 + 2
, which eventually results in 8
. Therefore, it’s better to enclose every argument in a parentheses.
Another trap that programmers usually fall prey to is using expressions as arguments that modify the behavior of the variable. For example:
#include <iostream>#define SQUARE_AREA(l) ((l) * (l))using namespace std;int main() {int len = 2;int area = SQUARE_AREA(len++);cout << "Area of Sqaure of length 2 is: " << area << endl;cout << "Len: " << len << endl;return 0;}
The area of a square with a length of 2
is being computed. The result should be 4
; however, the result of the above code is 6
. Here is an explanation as to why this occurs:
If SQAURE_AREA(l)
was a function, the len++
argument would pass the value 2
to the function and then increase the value of len
to 3
. But, in our case, the value of len
comes out to be 4
. This happens because the compiler first replaces SQUARE_AREA(len++)
with ((len++) * (len++))
. Then, the compiler evaluates the first len++
and the expression simplifies to (2 * (len++))
. At this point, the value of len
is 3
. Now ,the compiler evaluates the second len++
, the expression becomes (2 * 3)
, and the value of len
increses to 4
. As a result, the area is calculated to be 6
rather than 4
.