Explain the use of preprocessor in C programming language

  • 2020-05-09 18:55:52
  • OfStack

The biggest mark of preprocessing is uppercase, although this is not the standard, but when you use uppercase, for their own sake, but also for the sake of future generations.

In the general view of 1 preprocessor, the most used macro, here is a summary of the use of 1 preprocessor.

#include < stdio.h > #define MACRO_OF_MINE #ifdef MACRO_OF_MINE #else #endif

The above five pretreatment is most commonly seen, 1 represents a document containing 1 size, can be understood as many functions cannot be used without it, for example C language and no input into the input of standard, but the use of library functions to provide, so only contains stdio. h this header file, we can use those input and output functions. #define is a preprocessing mechanism that USES the second-highest frequency. It is widely used in the definition of constants, but it differs from the constants declared by const:


#define MAR_VA 100
const int Con_va = 100;
...
/* Define two arrays */
...
for(int i = 0;i < 10;++i)
{
  mar_arr[i] = MAR_VA;
  con_arr[i] = Con_va;
}

Difference 1: by definition MAR_VA can be used for array dimensions, while Con_va cannot
Difference 2: when used, the principle of MAR_VA is to find all the places where the MAR_VA is used, and replace them with values. That is to say, Con_va will have only 1 authentic n, while MAR_VA will have n authentic works (n is the number of times used), and the remaining 3 will be used in the protection header files.
Several useful macros for debugging come with the C language

S 37en__ and s 38en__ are used to show the current line number and the current file name S 39en__ and s 40en__ to show the current date and time S 41en__ (C99) is used to show the name of the current outer function

The five macros mentioned above can be used directly as values.

__STDC__

If you want to verify that your current compiler is compliant with the ISO standard, use it if it has a value of 1.


printf("%d\n", __STDC__);

Output: 1.

If you want to further determine whether the standard version used by the compiler is C99 or C89, you can use s 57ens 58en__, C99(199901)


printf("%d\n", __STDC_VERSION__);

Output: 199901

For # define

Preprocessor 1 normally only defines the same line, but if you add a backslash, you can read 1 straight down


 #define err(flag) \
   if(flag) \
    printf("Correctly")

As you can see, it's not added at the end; Not because macros are not required, but because we always use macros as functions, which are always required after function calls; Finally, in order not to cause confusion, we do not add by default in the macro definition; , which is used in code source files to prevent definition clutter.

Pretreatment can also bring some convenience


  #define SWAP1(a, b) (a += b, b = a - b, a -= b)
  #define SWAP2(x, y) {x ^= y; y ^= x; x ^= y}

To refer to the previous example, the macro notation of swapping two Numbers can effectively avoid the overhead of the function, since it expands the block of code directly at the call, so it is similar to the code directly embedded. However, occasionally there will be some dissonant errors, for beginners:


 int v1 = 10;
 int v2 = 20;
 SWAP1(v1, v2);
 SWAP2(v1, v2);// An error 

In the case of the above code block, why did SWAP2 report an error? For beginners like 1, it is often ignored to say, goto do... while and other keywords are rarely used, so SWAP1 is rarely written. Most of them focus on the similar error of SWAP2. The error lies in the fact that {} represents a code block, which does not need to be used. To conclude, this is where macro is most likely to make mistakes. Macro simply expands the code without doing any processing. For this, even the old hands often make mistakes.


 #define SWAP3(x ,y) do{ \
     x ^= y; y ^= x; x ^= y; \
     }while(0)

This allows you to safely use the curly braces in your code and, as previously agreed, make the use of macros look like functions.

But just as the so-called, false is always false, even if the macro is like a function, it is still not a function, if you really take it as a function, you will be confused at some point, or a classic example, compare the size:


 #define CMP(x, y) (x > y ? x : y)
 ...
 int x = 100, y = 200;
 int result = CMP(x, y++);
 printf("x = %d, y = %d, result = %d\n", x, y, result);

So if I execute this part of the code, what's going to be output? The answer is, no! At least we can't determine the value of result, so we expand the code to get it


 int result = (x > y++ ? x : y++);

It looks like y has to be incremented twice, and then result has to be 200. Really? C language standard for a certain program statement, an object can only be modified once, more than once, then the result is undetermined, determined by the compiler, except for the 3 operator ? : besides, there are &&, |, |, or in, or function parameter calls, switch control expressions, and control statements in for. Thus, we can see that the use of macros is also risky, so although macros are powerful, they should not be abused.

Macros, as mentioned earlier, are simply expanded, which can sometimes cause problems:


 #define MULTI(x, y) (x * y)
 ...
 int x = 100, y = 200;
 int result = MULTI(x+y, y);

See the problem? When expanded, it becomes: int result = x+y * y; It completely violates our original design idea. A better modification method is to put parentheses on each parameter: #define MULTI(x, y) ((x) * (y)), and then:


printf("%d\n", __STDC__);
0

This will go a long way towards solving part 1 of the problem.

If you are confident in your macros, you can nest macros, that is, you can use macros as arguments in an expression, but macros only expand the macros at this level. There is another way to expand macros at multiple levels


printf("%d\n", __STDC__);
1

Expands into:


printf("%d\n", __STDC__);
2

The application of macros

Since we don't know if macros are defined in some cases (NULL macros are an exception and can be defined repeatedly), we can use some preprocessor protection to prevent errors

  #ifndef MY_MACRO   #define MY_MACRO 10000   #endif

If MY_MACRO is defined, then do not execute the following statement, if it is not defined, then execute.

There are two useful operators in the use of macros, let's call them operators #, ##

For # we can think of the function of the # operator as converting macro arguments to strings.


  #define HCMP(x, y) printf(#x" is equal to" #y" ? %d\n", (x) == (y))
  ...
  int x = 100, y = 200;
  HCMP(x, y);

After a

 


printf("%d\n", __STDC__);
4

Note: you can add your own compiler options to see the code after the macro expansion. You can query the expansion options of GCC for details. This is especially true for the nesting of multiple macros, but I don't recommend it, so I won't go into it.

All that can be said is how to properly handle 1 bit of nested usage. The reason why you don't want to say more or use more is that the C preprocessor is just a freak
Take one typical example, the use of s = s = s = s = s = s = s = s = s = s = s = s = s = s = s = s = s = s = s


printf("%d\n", __STDC__);
5

Does that work? What would I say if I could.


printf("%d\n", __STDC__);
6

Don't ask me why, because I don't know how the C preprocessor really works either.

The first time I saw such a solution was in Windows core programming, and the book still gives me a lot of help, although it has gradually faded from the shelves

To sum up, the macro arguments are automatically converted to string constants by the preprocessor after the # operator, and escape is done by the preprocessor automatically, without the need to add escape symbols.

For # #
What it does is combine the parameters on both sides of this operator into a single complete tag. However, it is important to note that since the preprocessor is only responsible for expansion, the programmer must ensure the legitimacy of this tag


printf("%d\n", __STDC__);
7

First of all, I use the second one for habit reasons, but it doesn't hurt either one. What happens after the code is expanded?

         


result = have_define_1 + 3;

In my opinion, this is a bit C + + template in mind, though the original 10 points, but there is always a direction, with this method we can use a macro for similar but different function call, although we can use a function pointer array to store, but there are some functions need to know in advance, and if you want to achieve dynamic growth also needs to consume memory allocation, but different macros.


printf("%d\n", __STDC__);
9

As we add and subtract functions, we don't have to worry about how to find them. We just have to write down the number of each function, but again, don't abuse it.


   #define CAT(temp, i) (cat##i)
   //...
   for(int i = 0;i < 5;++i)
   {
     int CAT(x,i) = i*i;
     printf("x%d = %d \n",i,CAT(x,i));
   }

For macros, it is important to note that macros can only expand macros in the current layer when used. If you use macros nested within a macro and use macros as arguments to a macro, the macro will not fully expand and the macro as a parameter can only pass its name to the external macro

 


  #define WHERE(value_name, line) #value_name #line
  ...
  puts(WHERE(x, __LINE__)); //x = 11

Output: 11 __LINE__

Other precompiler instructions such as #program, #line, #error, and various conditional compilations are not covered here because there are no pitfalls or difficulties in their use.

C and C++ mixed programming

You can often see extern "C" in the source code. What does it do?
This is designed for mixed programming and is often found in C++ source code so that C++ can successfully call C's standard or non-standard functions.


  #if defined(__cplusplus) || defined(_cplusplus)
      extern "C" {
  #endif

      /** The main body of code **/

  #if defined(__cplusplus) || defined(_cplusplus)
      }
  #endif

This allows you to call C's code in C++.

The function that calls C++ in C needs to be aware that the overload function cannot be used, otherwise it will fail. Please refer to the implementation of C++ for the reason. It can also be called mangle


Related articles: