3.8 KiB
title |
---|
Macros in C |
Macros in C
A macro is a piece of code with a given name. When the name is used, it is replaced by the content of the macro. The #define
keyword is used to define new macros. It's followed by a name and a content. By convention, macro names are written in uppercase. There are two type of macros: Object-like
macros and Function-like
macros.
Why Macros?
The C compiler will go through your code and replace every occurrence of a macro with it's value. This begs the question, what is the point of using macros? The answer: macros are a tool for the programmer, not for the program.
If you have the number 365
hard-coded into your program, it becomes difficult for you and other people who may look at your code to understand what it means. If you #define DAYSINYEAR 365
and use that instead of the number, the code makes a lot more sense.
It's also beneficial if you have many instances of the same thing. If you'd used 2018
as the year in multiple places in your program, and then the year changed to 2019
, you would have to go and find every single line containing 2018
and change it, hoping you didn't miss any. With the macro #define YEAR 2018
, you can simply change the value of the macro and be confident all of the values have been updated accordingly.
Defining macros
The #define
keyword is used to define new macros. It's followed by a name and a content, but no equals sign. By convention, macro names are written in uppercase.
#define PI 3.14
If you use the macro this way:
printf("Value of PI: %d", PI);
Is the same as write this:
printf("Value of PI: %d", 3.14);
Undefining Macros
After defining macros you can also undefine them at any point. just Type
#undefine PI
This is used to use macros only for specific lines of code and again undefine it.
Function-like Macros
Function-like uses the same #define
keyword. The difference is that you use a pair of parentheses after the function name.
#define hello_world() printf("Hello World!")
So calling:
hello_world();
You get:
printf("Hello World!");
You can set parameters too:
#define hello(X) printf("Hello " X "!")
Now calling:
hello("World");
You get the equivalent of:
printf("Hello World!");
Special Operators in Macros
One can use the special operators # (stringize) and ## (concatenate) in macros for achieving unique functionality.
Stringizing Operator (#)
A macro's parameter preceded by a #
is converted and treated as a string token.
For example, we can define ERROR and WARN macros that print a LOG message.
While the LOG message gets prefixed with either an ERR
or a WARN
, respectively.
#define LOG(level, message) printf(#level ": " #message "\n")
#define ERROR(msg) LOG(FAIL, msg)
#define WARN(msg) LOG(WARN, msg)
Now, one can use it as
ERROR(Invalid settings); // Output-> FAIL: Invalid settings
WARN(Upper threshold); // Output-> WARN: Upper threshold
Concatenation (or token-pasting) Operator (##)
Using concatenation the parameters can be joined together to form one single token. Token-pasting is much more powerful in the sense that the resulting token could be an object defined in the C program.
#define NUM(x) number_##x
void foo() {
int number_one = 10;
int number_two = 15;
printf("%d + %d = %d\n", NUM(one), NUM(two), NUM(one) + NUM(two));
// Output-> 10 + 15 = 25
}