C language: preprocessing (macro definition and operator)

Posted by junrey on Mon, 21 Feb 2022 22:01:42 +0100

Preprocessing is an important function of C language, which is completed by preprocessor. When compiling a source file, the system will automatically call the preprocessing program to process the preprocessing part of the source program. After processing, it will automatically enter the compilation of the source program.

C language provides a variety of preprocessing functions, mainly dealing with # starting precompiled instructions, such as macro definition (#define), file include (#include), conditional compilation (#ifdef), etc. The program written by reasonable use of preprocessing function is easy to read, modify, transplant and debug, and is also conducive to modular program design.

Here, let's talk about macro definition (#define) in detail

#define

The instruction #define defines a macro name identifier and a character sequence (that is, a character set). Every time the macro name identifier is encountered in the source program, it is replaced with the defined character sequence. The identifier is called the macro name, the replacement process is called macro replacement, and the general form of the instruction is

#define macro_name char_sequence

Note that the statement does not have a semicolon. There can be any space between the identifier and the character sequence.

1. Macro constants

For example, if you want to use the character sequence LEFT to represent 1 and the character sequence RIGHT to represent 0, you can declare these two #define instructions

#define RIGHT 0 / / there is no need to add a semicolon at the end of the macro definition. Otherwise, the semicolon will be replaced. The macro definition does not allocate memory and has no type.
#define LEPT 1

In this way, when the source file is precompiled, it is replaced by 1 or 0 every time it encounters LEFT or right. For example, the following program outputs 1 0 1 on the screen

printf("%d %d %d\n", LEFT, RIGHT, RIGHT + 1);

The most common use of macro definition is to define the name of constants in the program. For example, when defining an array, use macro constant replacement. The advantage of this is that when we need to change the size of the array, we don't need to find each position in the cumbersome code to change it. We just need to change the macro definition and compile the program.

#define ARR_SIZE 100

int arr[ARR_SIZE];

2. Character sequence

Macro substitution simply replaces the identifier with the sequence of characters associated with it.

Therefore, if you want to define a prompt message to prompt for input errors, you can write the following code:

#define WARR_MES "input error!\n"

printf(WARR_MES);

Then the program encounters Warr when precompiling_ In MES, replace with the string "input error!\n". For the compiler, the actual form of printf() statement is:

printf("input error!\n");

If there is a macro name identifier in the string, it is not replaced. For example:

#define MAX 10

printf("MAX = MAX\n");

If the character sequence exceeds one line, you can continue the line with a backslash at the end of the line. For example:

#define TEST "this is a\
             long ward.\n"

printf(TEST);

3. Define macros of similar functions

#Another useful feature of the define command is that macro names can have arguments.

Whenever a macro name is encountered, the arguments used in its definition are replaced by the real elements in the program. This form of macro is called a macro similar to a function. For example:

#include <stdio.h>

#define ABS(a) ((a) < 0 ? - (a) : (a)) / / there must be no space between macro name and argument

int main()
{
    printf("abs(-1) = %d\n", ABS(-1));
    return 0;
}

The brackets containing a in the above procedure ensure the correct replacement in each case. For example, if the bracket around a is removed, the expression:

#include<stdio.h>
#define ABS(a) a < 0? -a:a
int main()
{
    ABS (10-20); //Macro replacement is only for replacement, without calculation and expression solution.
    return 0;
}

After macro replacement, it becomes:

 10-20< 0 ? -10-20 :10-20

Obviously, there will be errors

4. Preprocessing operator

There are three preprocessor operators: #, #@, ##. These operators are used with #define statements.

4.1# operator

Commonly known as the stringifie operator, the argument after it is converted to a double quoted string.

For example:

include <stdio.h>
#define mkstr(s) #s
int main()
{
    printf(mkstr(I Like C));
    return 0;
}

Then the compiler changes the printf() statement to:

 printf("I Like C");

4.2 ## operators

Called pasting operator, it is used to connect two symbols. For example:

include <stdio.h>
#define concat(a,b) a##b
int main(void)
{
    int xy = 10;
    printf("%d",concat(x,y));//The binding performed by the macro has no type and no type conversion.
    printf("%s",concat("hello","myworld"));
    return 0;
}

We can also simply analyze that the compiler replaces the printf() statement as follows

printf("%d",xy);
printf("%s","hellomyworld");

4.3 #@ operators

Its function is to character the arguments behind it. For example:

#define TO_CHAR(x) #@x
int main()
{
    //The number can be converted into characters through the character operator of the macro
    char a = TO_CHAR(1);
    char b = TO_CHAR(9);
    return 0;
}

5 #undef

#The undef instruction cancels the previously defined macro name# The general form of undef is:

#undef macro_name

For example, we can undefine the previously defined macro

#define ARR_SIZE 100

int arr[ARR_SIZE];

#undef ARR_SIZE

The ARR is not valid until the #undef statement is encountered_ Size has always been defined.

#The important purpose of undef is to limit macro names to code segments that only need them.

Topics: C