Interesting Facts About Macros And Preprocessors In C

Interesting Facts About Macros And Preprocessors In C

In C programming, lines that start with # are instructions for a special program called the preprocessor, which is called by the compiler. The preprocessor works before your program actually runs, during the compilation process.

Here are some interesting things about the C preprocessor:

1) When you use “#include,” it’s like taking the content of another file and putting it into your program. Think of it like copying and pasting. You can tell the preprocessor to look for that file in a standard place (using < and >) or in your current folder (using double quotes).

2) When you use “#define” to create a constant, the preprocessor replaces that constant with a specific value wherever you use it in your program. For example, if you define “max” as 100, every time you use “max” in your code, it’s replaced with 100. This makes your code easier to read and understand.

In a nutshell, the preprocessor is like a helper that simplifies your code and makes it easier for the computer to understand before your program runs.

Example-to illustrate that max is defined as 100



#include <stdio.h>
#define max 100
int main()
{
    printf("max is %d", max);
    return 0;
}

Output

max is 100

3)Macros in C can indeed take function-like arguments, and they don’t perform data type checking. This means you can use macros like the one you mentioned, “INCREMENT,” for variables of any data type. The macro doesn’t care about the data type of the argument; it simply performs text substitution.

#include <stdio.h>
#define INCREMENT(x) ++x
int main()
{
    char* ptr = "Skill Vertex ";
    int x = 10;
    printf("%s  ", INCREMENT(ptr));
    printf("%d", INCREMENT(x));
    return 0;
}

Output

kill Vertex  11

4) Macro arguments are not analyzed before macro expansion. Refer to the program given below

#include <stdio.h>
#define MULTIPLY(a, b) a* b
int main()
{
    // The macro is expanded as 2 + 3 * 3 + 5, not as 5*8
    printf("%d", MULTIPLY(2 + 3, 3 + 5));
    return 0;
}
// Output: 16

Output

16

Another way to solve this program :

#include <stdio.h>
// here, instead of writing a*a we write (a)*(b)
#define MULTIPLY(a, b) (a) * (b)
int main()
{
    // The macro is expanded as (2 + 3) * (3 + 5), as 5*8
    printf("%d", MULTIPLY(2 + 3, 3 + 5));
    return 0;
}

Output

40

5) The tokens that are passed to macros will be linked with the help of operator # # which is referred to as a Token-Pasting operator.

#include <stdio.h>
#define merge(a, b) a##b
int main() { printf("%d ", merge(12, 34)); }

Output

1234

6) The token that is passed to macro will be transferred to a string literal with the # before it.



#include <stdio.h>
#define get(a) #a
int main()
{
    // Skillvertex is changed to "Skillvertex "
    printf("%s", get(Skillvertex));
}

Output

Skillvertex

7) The Macros will be noted in multiple lines with the ‘\’. However, the last line doesn’t require ‘\’



#include <stdio.h>
#define PRINT(i, limit)                                    \
    while (i < limit) {                                    \
        printf("Skillvertex ");                              \
        i++;                                               \
    }
int main()
{
    int i = 0;
    PRINT(i, 3);
    return 0;
}

Output

Skillvertex  Skillvertex  Skillvertex

8) We have to ignore the macros with the arguments as it can create problems sometimes. Therefore, Inline functions should be considered due to the type-checking parameter evaluation in inline functions. Thus, From C99 onward, inline functions are supported by C language. 

Refer to the program given below. We can understand that the possible output will be 1, however, it shows 36 as the output

#include <stdio.h>
 
#define square(x) x* x
int main()
{
    // Expanded as 36/6*6
    int x = 36 / square(6);
    printf("%d", x);
    return 0;
}

Output

36

Another way to get the expected output as 1 is given below:

#include <stdio.h>
 
#define square(x) (x * x)
int main()
{
    // Expanded as 36/(6*6)
    int x = 36 / square(6);
    printf("%d", x);
    return 0;
}

Output

1

Thus, we can conclude that inline functions can be used in the above program to get the desired result. Refer to the program given below how to use inline functions. Also, the program which is provided in point 4 can be corrected using the inline functions.

#include <stdio.h>
 
static inline int square(int x) { return x * x; }
int main()
{
    int x = 36 / square(6);
    printf("%d", x);
    return 0;
}

Output

1

9) Preprocessors in C and C++ support conditional compilation using #if, #ifdef, #ifndef, #elif, and #else directives. These directives are used to conditionally include or exclude portions of code from the compilation process based on specified conditions.

int main()
{
#if VERBOSE >= 2
    printf("Trace Message");
#endif
}

Output

No Output

10) In C and C++ programming, it’s common for header files to be included multiple times, either directly or indirectly through other header files. This can lead to issues like redeclaration of the same variables or functions, which can cause compilation errors.

To address this problem, preprocessor directives like #define, #ifdef, and #ifndef are often used in header files. Here’s how they are typically employed

11) Standard macros functions to print program file ( __FILE), Date of compilation (__DATE__), Time of Compilation (__TIME__) and Line Number in C Code (__LINE__)

#include <stdio.h>
 
int main()
{
    printf("Current File :%s\n", __FILE__);
    printf("Current Date :%s\n", __DATE__);
    printf("Current Time :%s\n", __TIME__);
    printf("Line Number :%d\n", __LINE__);
    return 0;
}

Output

Current File :/usr/share/IDE_PROGRAMS/C/other/081c548d50135ed88cfa0296159b05ca/081c548d50135ed88cfa0296159b05ca.c
Current Date :Sep  4 2019
Current Time :10:17:43
Line Number :8

12) Defined Macros can be removed using the #undef MACRO_NAME

#include <stdio.h>
#define LIMIT 100
int main()
{
    printf("%d", LIMIT);
// removing defined macro LIMIT
#undef LIMIT
    // Next line causes error as LIMIT is not defined
    printf("%d", LIMIT);
    return 0;
}

In the program given below, limit as an integer variable is declared after removing previously defined macro LIMIT

#include <stdio.h>
#define LIMIT 1000
int main()
{
    printf("%d", LIMIT);
// removing defined macro LIMIT
#undef LIMIT
    // Declare LIMIT as integer again
    int LIMIT = 1001;
    printf("\n%d", LIMIT);
    return 0;
}

Output

1000
1001

Interesting fact about macro using (#undef) is described using the program given below:

#include <stdio.h>
// div function prototype
float div(float, float);
#define div(x, y) x / y
 
int main()
{
    // use of macro div
    // Note: %0.2f for taking two decimal value after point
    printf("%0.2f", div(10.0, 5.0));
// removing defined macro div
#undef div
    // function div is called as macro definition is removed
    printf("\n%0.2f", div(10.0, 5.0));
    return 0;
}
 
// div function definition
float div(float x, float y) { return y / x; }

Output

2.00
0.50

FAQ- Interesting Facts about Macros and Preprocessors in C

Q1. What is the purpose C preprocessor macros?

Ans. The C preprocessor is a tool that transforms your code before compilation. It handles tasks like including header files, expanding macros, and performing conditional compilation. It makes your code more readable and prepares it for the compiler.

Q2. Which is faster preprocessor or macro?

Ans. When it comes to macros in C/C++, one of the main advantages is speed – they lead to faster execution. Macros are expanded (replaced with their definitions) directly in the code each time they are used. In contrast, a function definition is processed only once, no matter how many times it’s called. This speed advantage makes macros suitable for certain performance-critical scenarios.

Q3. Can we change macro value in C?

Ans. In C, when you define a macro, it stays effective in your program from the moment you define it until you change it, remove it, or finish compiling your program. So, if you change the value of a macro, that new value will be used throughout your program unless you change it again or until you finish writing your code. This can be handy for controlling how certain parts of your program work.

Hridhya Manoj

Hello, I’m Hridhya Manoj. I’m passionate about technology and its ever-evolving landscape. With a deep love for writing and a curious mind, I enjoy translating complex concepts into understandable, engaging content. Let’s explore the world of tech together

Leave a Comment