Macros in C
The C preprocessor, which runs source code before the compiler, can employ macros. Macros are defined with #define.
Text substitution is a macro’s main purpose. The preprocessor substitutes a given string or series of tokens for the macro name it finds in the code after it has been defined. The compiler works on the extended code since this substitution takes place before the compiler sees the code.
Types of macros
Two primary categories of macros exist:
Symbolic Constants
These are straightforward, argument-free text replacements. Usually, they are employed to give constant values significant names.
- How it works: Every time the macro name appears, the preprocessor substitutes the defined text.
- Example: The preprocessor would change the line float area = PI * radius * radius; to float area = 3.14159 * radius * radius; prior to compilation. Printf(“%s”); also becomes printf(“%s”);, which in turn becomes printf(“%s”).
Macros with Arguments (Parameterized Macros)
These specify an argument-accepting text replacement pattern. Although these are text substitutions, they appear to be function calls.
- How it works: The preprocessor inserts the supplied values into the specified text pattern when the macro is activated. To prevent unexpected outcomes from operator precedence, brackets are essential around the definition’s arguments and throughout. The macro name and the initial parenthesis ( in the #define line must not be separated by a space.
- Example: The preprocessor would change the line int result = SQUARE(num + 1); to int result = ((num + 1) * (num + 1)); before to compilation.
Functions are not macros. By replacing text, they can reduce the overhead of a function call and speed up code execution. In contrast to functions, which need certain types of arguments (although the preprocessor does not do type checking), they can also be used to design operations that operate on inputs of any type. However, if macros are used frequently, they can make a program larger and can result in difficult-to-find problems because of erroneous replacement, particularly when side-effect expressions (like i++) are used as arguments.
Other preprocessor features
Alongside macros, other preprocessing features that are frequently discussed include:
- #include: used to add content from another file (such as header files) to the source file that is currently open.
- #undef: For deleting a macro definition.
- #: A macro parameter can be stringified to become a string literal.
- ##: Two tokens are concatenated.
Example
#include <stdio.h> // Include header for input/output functions
// Symbolic Constant Macro: Defines PI as a text replacement for the value 3.14159
#define PI 3.14159
// Parameterized Macro: Defines SQUARE(x) to compute the square of x
// Parentheses around x and the entire expression ((x) * (x)) are crucial for safety
#define SQUARE(x) ((x) * (x))
int main(void) {
float radius = 5.0;
float area;
int num = 4;
int result;
// Using the symbolic constant PI
// Before compilation, the preprocessor replaces PI with 3.14159
area = PI * radius * radius; // This becomes: area = 3.14159 * radius * radius;
// Using the parameterized macro SQUARE
// Before compilation, the preprocessor replaces SQUARE(num + 1) with ((num + 1) * (num + 1))
result = SQUARE(num + 1); // This becomes: result = ((num + 1) * (num + 1));
printf("Area of circle with radius %.2f: %f\n", radius, area); // Use printf for output
printf("Square of %d is %d\n", num + 1, result);
printf("Direct use of macro: SQUARE(5) = %d\n", SQUARE(5)); // SQUARE(5) becomes ((5) * (5))
return 0;
}
Output
Area of circle with radius 5.00: 78.539749
Square of 5 is 25
Direct use of macro: SQUARE(5) = 25
You can also read What Are C Command Line Arguments & How To Access It?