In the C language, #define is a preprocessor directive used to define macros. Essentially, it replaces the macro name with specified content before compilation, and it can be categorized into two core usages: non-parameterized macros and parameterized macros.
1. Non-parameterized macros (constant definitions) are the most common scenario, where the macro name replaces constants (such as numbers or strings) to improve code readability and maintainability. The format is: #define macro_name replacement_content (no semicolon after the replacement content). Example:
#include <stdio.h>
// Define Pi and maximum array length
#define PI 3.1415926
#define MAX_SIZE 100
int main() {
printf("PI = %.7f\n", PI); // Replaced before compilation with printf("PI = %.7f\n", 3.1415926);
int arr[MAX_SIZE]; // Replaced with int arr[100];
return 0;
}
2. Parameterized macros (similar to functions) define macros with parameters, achieving simple logical “function-like” replacements (without function call overhead, but care must be taken with operator precedence). The format is: #define macro_name(parameter_list) replacement_content (no space between the parameter list and macro name). Example:
#include <stdio.h>
// Define a macro to find the maximum of two numbers
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main() {
int x = 5, y = 8;
printf("Max: %d\n", MAX(x, y)); // Replaced with ((5) > (8) ? (5) : (8)), result is 8
return 0;
}
Note: The replacement content should be enclosed in parentheses to avoid errors due to operator precedence (e.g., #define MUL(a,b) a*b would result in incorrect evaluation for MUL(2+3,4) as it would become 2+3*4; changing it to #define MUL(a,b) ((a)*(b)) can avoid this issue).
3. Special usage: multi-line macros. If the replacement content of a macro needs to span multiple lines, add a \ (backslash) at the end of each line to continue the line. Example:
#include <stdio.h>
#define PRINT_INFO(name, age) \
printf("Name: %s\n", name); \
printf("Age: %d\n", age);
int main() {
PRINT_INFO("Alice", 20); // Replaced with two printf statements
return 0;
}
Key Features:
- No type checking: Macro replacement is a pure text replacement and does not involve variable types; it is necessary to manually ensure parameter type matching.
- Executed before compilation: Macro replacement occurs during the preprocessing stage, and by the time of compilation, the macro names are no longer present, making it impossible to use
sizeofto get the “size” of a macro. - Can be undefined: Use
#undef macro_nameto cancel a defined macro, after which the macro can be redefined.
The core purpose of macro definitions (#define) is to enhance code readability, maintainability, and simplify repetitive operations. This can be summarized in the following four key reasons:
- Enhance readability: Use meaningful macro names instead of meaningless constants (like numbers or strings) to make the code easier to understand. For example,
#define MAX_STUDENTS 50is clearer than just writing50, as the reader immediately knows this represents the “maximum number of students” rather than a random number. - Simplify modifications: When a value (like a configuration parameter or constant) needs to be used in multiple places, macro definitions allow for “unified management.” If this value needs to be changed, you only need to modify the “replacement content” of the macro definition, avoiding the need to change every reference individually, thus preventing omissions or errors. For example, if
MAX_STUDENTSchanges from50to100, you only need to modify the macro definition, and all arrays and conditions usingMAX_STUDENTSwill automatically update. - Reduce duplicate code: Achieve “code reuse”. For simple, frequently used logic (like calculations or printing), parameterized macros can replace small functions, avoiding the need to repeatedly write the same code. For example,
#define MIN(a,b) ((a)<(b)?(a):(b))can be used in multiple places to find the minimum value without needing to write the ternary operator each time or incurring the overhead of function calls (macros are replaced before compilation, with no function stack costs). - Adapt to different scenarios: Achieve “conditional compilation”. Macro definitions are often combined with conditional compilation (
#if/#ifdef, etc.) to allow the code to adapt to different environments (like different operating systems or hardware platforms). For example:
#define OS_WINDOWS 1 // If for Linux, change to #define OS_LINUX 1
#ifdef OS_WINDOWS
printf("Running on Windows system\n");
#else
printf("Running on other systems\n");
#endif
By modifying the macro definition, you can quickly switch the execution branch of the code without changing the core logic.