Learn C #18: Understanding Preprocessors and Macros

 


C Macros

In this tutorial we will learn about preprocessors and macros in C.

This is important.

So you can understand the process behind the C program code before compiling it.

So what are preprocessors and macros ?

How to use it?

Let's learn!

What are Preprocessors and Macros?

Before the program code is compiled into binary, the program code is processed first by the preprocessor.

The results of the process from the preprocessor are C program code that is ready to be compiled.

preprocessor on c

Why does it have to be done with a preprocessor?

So that we don't write code manually.

What does that mean?

Gini..

Take a look at this program code:

#include <stdio.h>

void main(){
  printf("Hello World!\n");
}

In this program, there is a macro:

#include <stdio.h>

The function of this macro is to tell the preprocessor to insert all the code in the file stdio.hinto our program code.

So we can use the functions printf()in it.

If there is no preprocessor , then we have to enter it manually. You can copy and paste all the contents of the code stdio.hinto our program code.

Want it like that?

Obviously not, it's tiring work.

That's why we need a preprocessor .

So..

Preprocessor is a process carried out before the program is compiled based on the given macros. The preprocessor output is program code, not a binary file. This program code will later be compiled by the compiler.

preprocessor on c

If we want to see the preprocessor results, we can use the cppor command gcc -E.

Example:

cpp hello_world.c

or:

gcc -E hello_world.c

So the result is:

preprocessor results

In the results of this preprocessor, all the existing code is stdio.hincluded in the code that we write.

This is because we use macros #include <stdio.h>.

So..

Macros are codes to provide instructions to the preprocessor.

Example of macros:

#include <stdio.h>

This macro is for giving commands to the preprocessor:

"Hi preprocessor, enter all the existing program code stdio.hinto this program code."

Apart from macros, #includethere are also other macros.

Macro DirectivesMacro Functions
#defineDefines constants and functions
#includeto add code to the program
#undefto delete macros that have been defined
#ifdefto check whether the macro has been defined
#ifndefto check whether the macro has not been defined
#ifto create an if condition
#elseto create an alternative to if
#elifto create an else if condition
#endifto end the if condition block
#errorto print error messages to stderr
#pragmato give instructions to the compiler.

Macro directives are symbols or words used to create or define macros.

Macro definitions can be written anywhere, either inside the main function or outside. Can be in the header file or source file.

To better understand, let's discuss it with examples.

#define and #undefine directives

As discussed in the table above...

..directive #defineand #undefinefunctions to define and delete macro definitions.

Example:

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

It means:

Define constants with names SCREEN_WIDTHwith values 800​​and SCREEN_HEIGH 600.

If a macro has been defined in another file, we can redefine it by deleting the definition first with #undef.

Example:

#undef  FILE_SIZE
#define FILE_SIZE 42

Apart from defining constants, #definewe can also use directives to define functions.

Example:

#define square(sisi) ((sisi) * (sisi))
#define MAX(x,y) ((x) > (y) ? (x) : (y))

There are two macros in the form of functions that we create, namely: square()and MAX().

If we want to use this macro, we can call it like a normal function.

Example:

#include <stdio.h>

// mendefinisikan macro
#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
  // menggunakan macro
  printf("Max between 20 and 10 is %d\n", MAX(10, 20));  
  return 0;
}

If compiled and run, the output results are:

Max between 20 and 10 is 20

So it is a directive #defineand #undefinefunctions to create and delete macros.

Predefined Macros

Predefined macros are macros that already exist or have been defined on our computer. We just need to use it.

Example of predefined macros:

  • __DATE__contains the current date;
  • __TIME__contains the current time;
  • __FILE__contains the file name of the program code;
  • __LINE__contains the program line number.
  • __STDC__contains 1if the program was compiled to ANSI standards.

Example of use:

Create a new program file with a name predefined_macro.cwith the following contents.

#include <stdio.h>

void main() {

   printf("File : %s\n", __FILE__ );
   printf("Date : %s\n", __DATE__ );
   printf("Time : %s\n", __TIME__ );
   printf("Line : %d\n", __LINE__ );
   printf("ANSI : %d\n", __STDC__ );

}

The result:

File : predefined_macro.c
Date : May 16 2022
Time : 03:36:24
Line : 8
ANSI : 1

Condition Directive

We can create conditions with macro directives, there are several directives provided to create conditions:

  • #iffor conditions if;
  • #elsefor conditions else;
  • #eliffor conditions else if;
  • #endifto close or end if;
  • #ifdefto check if the macro has been defined;
  • #ifndefto check if the macro has not been defined.

Example of use:

#include <stdio.h>

#ifndef DEBUG
#define DEBUG true
#endif

void main(){
  #if defined(DEBUG)
  printf("Debugging mode is on\n");
  #else
  printf("Debugging mode is off\n");
  #endif
}

So the preprocessor results:

void main(){
  printf("Debugging mode is on\n");
}

So we can choose which code will be processed based on certain conditions.

Operators on Macros

Macros have 4 operators that can be used:

1. Connection Operator

The concatenation operator uses the backslash symbol (\), its function is to connect macro definitions if there is more than one line.

Example:

#define  message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

2. Stringize Operator (#)

The stringize operator uses the fence symbol ( #), which functions to convert macro parameters into string text.

#include <stdio.h>

#define  message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

int main(void) {
   message_for(Petani, Kode);
   return 0;
}

Maybe you will ask...

When using a macro like this:

message_for(Petani, Kode);

Why doesn't the program error, there are no quotation marks there?

Remember:

Macros are processed by the preprocessor, not the compiler. So when it is compiled the program will be able to run because preprocessing has been done beforehand.

We can check the preprocessor results with the command cpp.

cpp kode_program.c

So the result is:

int main(void) {
   printf("Petani" " and " "Kode" ": We love you!\n");
   return 0;
}

3. Token Pasting Operator

The token pasting operator functions to retrieve the name of a variable or parameter given to a macro. This operator uses the double fence symbol ( ##).

Example:

#include <stdio.h>

#define tokenpaster(n) printf ("%d", token_##n)

int main(void) {
   int petani_kode = 40;
   tokenpaster(petani_kode);
   return 0;
}

So the preprocessor results:

int main(void) {
   int petani_kode = 40;
   printf ("%d", token_petani_kode);
   return 0;
}

4. Operator defined()

Operators defined()function to check the condition of a macro. Whether the macro has been defined or not. This is the same as the #ifdefand directive #ifndef.

Example:

#include <stdio.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   printf("Here is the message: %s\n", MESSAGE);  
   return 0;
}

So the preprocessor results:

int main(void) {
   printf("Here is the message: %s\n", "You wish!");
   return 0;
}

Parameters for Macros

Parameters are special variables used by macros for processing. Usually we need it when creating macros in the form of functions.

Example:

#include <stdio.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

void main(void) {
   printf("Max between 20 and 10 is %d\n", MAX(10, 20));
   return 0;
}

So the preprocessor results:

void main(void) {
   printf("Max between 20 and 10 is %d\n", ((10) > (20) ? (10) : (20)));
   return 0;
}

What is next?

Macros and preprocessing are features that help us in creating C program code. So we can create shorter program code rather than having to write all the code over and over again.

Next, please learn about header files in C to create modular programs that can be reused with macros #include.

If you are still confused, please ask in the comments.

Post a Comment

Previous Post Next Post