当前位置:网站首页>Detailed explanation of C language conditional compilation

Detailed explanation of C language conditional compilation

2022-06-13 01:56:00 richardgann

The preprocessing process scans the source code , Make a preliminary transformation of it , Generate new source code for the compiler . It can be seen that the preprocessing process precedes the compiler to process the source code .
stay C In language , There is no inherent mechanism to perform some of the following functions : Include other source files at compile time 、 Defining macro 、 Decide whether to include some code at compile time according to the conditions . To do this , You need to use a preprocessor . Although at present most compilers contain preprocessors , But they are generally considered compiler independent . The preprocessing process reads the source code , Check the statement and macro definitions that contain preprocessing instructions , And the source code response conversion . Preprocessing also removes comments and extra white space from the program .
The preprocessing instruction is based on # The line of code that begins with the .# The number must be the first character on the line except any white space character .# Next is the instruction keyword , In keywords and # Any number of white space characters are allowed between numbers . The whole line of statements constitutes a preprocessing instruction , This instruction will do some conversion to the source code before the compiler compiles . Here are some preprocessing instructions :

        Instructions              purpose
         #           Empty command , No effect
         #include    Contains a source file
         #define     Defining macro
         #undef      Cancel defined macro
         #if         If the given condition is true , Then compile the following code
         #ifdef      If the macro has been defined , Then compile the following code
         #ifndef     If the macro is not defined , Then compile the following code
         #elif       If the front #if Given conditions are not true , The current condition is true , Then compile the following code
         #endif      End one #if……#else Conditional compilation block
         #error      Stop compiling and display error messages

One 、 File contains
    #include The function of the preprocessing instruction is to expand the included file at the instruction . Inclusion can be multiple , That is to say, an included file can also contain other files . standard C The compiler supports at least octet nested inclusion .
    The preprocessing process does not check whether a file has been included in the conversion unit and prevents multiple inclusion of it . In this way, when the same header file is included multiple times , Different effects can be achieved by giving compile time conditions . for example :

        #define AAA
        #include "t.c"
        #undef AAA
        #include "t.c"

    To avoid header files that can only be included once being included multiple times , You can use compile time conditions in the header file to control . for example :
        /*my.h*/
        #ifndef MY_H
        #define MY_H
          ……
        #endif

    There are two formats for including header files in a program :
        #include <my.h>
        #include "my.h"
     The first method is to enclose the header file with angle brackets . This format tells the preprocessor to search the included header file in the header file of the compiler or external library . The second method is to enclose the header file with double quotation marks . This format tells the preprocessor to search the included header file in the source code file of the currently compiled application , If you can't find it , Then search the header file of the compiler .
    The reason for using two different inclusion formats is , The compiler is installed in a public subdirectory , The compiled applications are in their own private subdirectories . An application contains both the common header file provided by the compiler , Also contains custom private header files . The adoption of two different inclusion formats enables the compiler to distinguish a set of common header files among many header files .

Two 、 macro
    A macro defines an identifier that represents specific content . The preprocessing replaces the macro identifier that appears in the source code with the value of the macro definition . The most common use of macros is to define global symbols that represent a value . The second use of macros is to define macros with parameters , Such macros can be called like functions , But it expands the macro at the call statement , The actual parameters in the call are used to replace the formal parameters in the definition .
    1.#define Instructions
        #define Preprocessing instructions are used to define macros . The simplest form of this instruction is : First, the deity gives an identifier , Then give the code represented by this identifier . In the following source code , Just use this code to replace the identifier . This macro extracts some global values to be used in the program , Assign some memory identifiers .
            #define MAX_NUM 10
            int array[MAX_NUM];
            for(i=0;i<MAX_NUM;i++)  /*……*/
        
         In this case , For those who read the program , Symbol MAX_NUM It has a specific meaning , The value it represents gives the maximum number of elements that the array can hold . This value can be used multiple times in a program . As an agreement , It is customary to define macros in all capital letters , In this way, it is easy to distinguish the macro identifier of program red from the general variable identifier . If you want to change the size of the array , Just change the macro definition and recompile the program .
        The value represented by a macro can be a constant expression , It is allowed to include macro identifiers that have been previously defined . for example :
            #define ONE 1
            #define TWO 2
            #define THREE (ONE+TWO)
        Notice that the macro definition above uses parentheses . Although they are not necessary . But out of caution , It should be bracketed . for example :
            six=THREE*TWO;
        The preprocessing process converts the above line of code into :
            six=(ONE+TWO)*TWO;
        Without that bracket , Turn it into six=ONE+TWO*TWO; 了 .
        Macros can also represent a string constant , for example :
            #define VERSION "Version 1.0 Copyright(c) 2003"
    2. Parameterized #define Instructions
        Macros with arguments and function calls look a little similar . Take an example :
            #define Cube(x) (x)*(x)*(x)
        Any numeric expression or even function call can be used to replace parameters x. Here again, I would like to remind you to pay attention to the use of parentheses . The expanded macro is completely enclosed in a pair of parentheses , And the parameters are also contained in parentheses , This ensures the integrity of macros and parameters . Look at a usage :
            int num=8+2;
            volume=Cube(num);
        Expand to (8+2)*(8+2)*(8+2);
        If you don't have those parentheses, it becomes 8+2*8+2*8+2 了 .
        The following usage is unsafe :
            volume=Cube(num++);
        If Cube It's a function , The above writing is understandable . however , because Cube Is a macro , So there will be side effects . The erasure here is not a simple expression , They will produce unexpected results . They unfold like this :
            volume=(num++)*(num++)*(num++);
        Obviously , The result is 10*11*12, instead of 10*10*10;
        So how to use safely Cube Where's macro ? Operations that may have side effects must be moved outside the macro call :
            int num=8+2;
            volume=Cube(num);
            num++;
    3.# Operator
        Appears in the macro definition # Operator converts the following argument to a string . Sometimes this usage is used as # Called the stringing operator . for example :

            #define PASTE(n) "adhfkj"#n

            main()
            {
               printf("%s\n",PASTE(15));
            }
        In the macro definition # Operator tells the preprocessor , Convert any parameter passed to the macro in the source code into a string . So the output should be adhfkj15.
    4.## Operator
        ## Operator is used to join parameters together . The preprocessor will appear in ## The parameters on both sides are combined into one symbol . See the following example :

            #define NUM(a,b,c) a##b##c
            #define STR(a,b,c) a##b##c

            main()
            {
                printf("%d\n",NUM(1,2,3));
                printf("%s\n",STR("aa","bb","cc"));
            }

        Finally, the output of the program is :
                 123
                 aabbcc
        Don't worry , Unless it is necessary or the macro usage is just relevant to the work at hand , Otherwise few programmers would know ## Operator . Most programmers have never used it .

3、 ... and 、 Conditional compilation instructions
    Conditional compilation instructions will determine which code is compiled , And which are not compiled . Compilation conditions can be determined by the value of the expression or whether a particular macro is defined .
    1.#if Instructions
        #if The instruction detects a constant expression following the creation of another key . If the expression is true , Then compile the following code , Know to appear #else、#elif or #endif until ; Otherwise, do not compile .
    2.#endif Instructions
        #endif Used to terminate #if Preprocessing instruction .

            #define DEBUG 0
            main()
            {
                #if DEBUG
                    printf("Debugging\n");
                #endif
                    printf("Running\n");
            }

        Because the program definition DEBUG Macro representative 0, therefore #if The condition is false , Do not compile subsequent code until #endif, So the program directly outputs Running.
        If you remove #define sentence , The effect is the same .
    3.#ifdef and #ifndef
        #define DEBUG

        main()
        {
            #ifdef DEBUG
                printf("yes\n");
            #endif
            #ifndef DEBUG
                printf("no\n");
            #endif
        }
        #if defined Equivalent to #ifdef; #if !defined Equivalent to #ifndef
    4.#else Instructions
        #else An instruction is used for a #if After the instruction , When the front #if When the condition of the instruction is not true , Just compile #else Later code .#endif The instruction will point to the condition block above .

        #define DEBUG

        main()
        {
            #ifdef DEBUG
                printf("Debugging\n");
            #else
                printf("Not debugging\n");
            #endif
                printf("Running\n");
       }

    5.#elif Instructions
        #elif The preprocessing instructions synthesize #else and #if Role of instructions .

        #define TWO

        main()
        {
            #ifdef ONE
                printf("1\n");
            #elif defined TWO
                printf("2\n");
            #else
                printf("3\n");
            #endif
        }
        The program is well understood , The output is zero 2.

    6. Other standard directives
        #error Instruction will cause the compiler to display an error message , Then stop compiling .
        #line Instructions can change the file and line numbers that the compiler uses to indicate warnings and errors .
        #pragma The directive has no formal definition . The compiler can customize its purpose . A typical usage is to prohibit or allow some annoying warning message . 

原网站

版权声明
本文为[richardgann]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202280548347269.html