Macros are preprocessor directives defined using the #define directive that replace code or values before the compilation process begins. They are commonly used to define constants and create reusable code snippets.
- Creates symbolic constants or function-like macros that are expanded during preprocessing.
- Macros are expanded as plain text, so they do not provide compile-time type safety.
#include <iostream>
using namespace std;
// Define a macro to calculate the square of a number
#define SQUARE(x) (x * x)
int main()
{
int n = 7;
int result = SQUARE(n); // Expands to: (n * n)
cout << "Square of " << n << " is " << result;
return 0;
}
Output
Square of 7 is 49
Syntax
#define MACRO_NAME macro_definition
- MACRO_NAME: It is the name we give to the macro, that's usually in uppercase to differentiate it from ordinary C++ identifiers.
- macro_definition: It is the code that the preprocessor will substitute whenever the macro is used.
Types of Macros in C++
Macros can be classified into four types in C++:
1. Object-Like Macros
These are used to define constant values â like replacing a word with a fixed number or text.
#include <iostream>
using namespace std;
// Define a constant for the value of PI
#define PI 3.14159
int main()
{
double radius = 4.0;
// Calculate the area of the circle
double area = PI * radius * radius;
cout << "Area of circle with radius " << radius
<< " is " << area;
return 0;
}
Output
Area of circle with radius 4 is 50.2654
2. Function-Like Macros
These macros look like functions, but they are just text replacements.
// C++ program to illustrate the function like macros
#include <iostream>
using namespace std;
// Define a macro to print a value
#define PRINT(x) cout << "Value is: " << x
int main()
{
int value = 42;
// Print the value using the PRINT macro
PRINT(value);
return 0;
}
Output
Value is: 42
3. Conditional Macros (for Conditional Compilation)
These are used to control which parts of the code should be compiled, based on whether something is defined or not.
#include <iostream>
// Define a macro named DEBUG
#define DEBUG
int main() {
int x = 5, y = 10;
int sum = x + y;
// This block will only be compiled if DEBUG is defined
#ifdef DEBUG
std::cout << "[DEBUG] x = " << x << std::endl;
std::cout << "[DEBUG] y = " << y << std::endl;
std::cout << "[DEBUG] sum = " << sum << std::endl;
#endif
// Always compiled
std::cout << "Sum: " << sum << std::endl;
return 0;
}
Output
[DEBUG] x = 5 [DEBUG] y = 10 [DEBUG] sum = 15 Sum: 15
Predefined Macros
Predefined macros are special macros that are already built into the C++ compiler.
You don't need to define them â they are automatically available in your program.
The following are some commonly used predefined macros in C++:
- __LINE__: This macro expands to the current line number in the source code.
- __FILE__: This macro expands to the name of the current source file.
- __DATE__: This macro expands to a string that represents the date of compilation.
- __TIME__: This macro expands to a string that represents the time of compilation.
Example
In this example, __LINE__ is replaced with the current line number, __FILE__ with the source file name and __DATE__ with the compilation date. These can be handy for debugging and logging.
// C++ program to illustrate the predefined macros
#include <iostream>
using namespace std;
int main()
{
// Display the current line number and the source file
// name
cout << "This is line " << __LINE__ << " in file "
<< __FILE__ << "\n";
// Display the compilation date
cout << "Compiled on " << __DATE__;
return 0;
}
Output
This is line 10 in file ./Solution.cpp Compiled on Nov 7 2023
Advantages
Macros provide a simple way to improve code reusability, flexibility, and performance by replacing code during preprocessing.
- Promote code reuse by eliminating repetitive code.
- Easy to update, as changes in a macro are reflected wherever it is used.
- Support conditional compilation using directives like #ifdef and #ifndef.
- Can improve performance by avoiding function call overhead for small operations.
Disadvantages
Although macros are useful, improper use can make programs harder to understand and debug.
- No type checking, which can lead to compilation or runtime errors.
- May produce unexpected behavior due to lack of proper expression evaluation.
- Harder to debug, as macros are expanded before compilation.
- Excessive use can reduce code readability and maintainability.