C and Pointers (10) Preprocessor

Preprocessor
1, the first step of compiling a C program is the preprocessing stage, and perform some text operations before compiling the source code: 1)
Delete comments;
2) Insert the contents and definitions of the files included in the #include directive;
3 ) to replace the symbols defined by the #define directive;
4) to determine whether the code is compiled according to the conditional compilation directive.

2. The preprocessor defines some string constants, confirms the source of the debug output, and adds version information to the program.

__FILE__,编绎的源文件名
__LINE__,文件当前行号
__DATE__,文件编绎日期
__TIME__,文件编绎时间
__STDC__,用于ANSI和非ANSI环境根据条件编绎,如果编绎器遵循ANSI C,值为1,否则未定义。

#define
1, #define can replace any text into the program, not limited to numeric literal constants. If the name in the definition is too long, it can be divided into several lines. Except for the last line, add a backslash at the end of each line, adjacent String constants are automatically concatenated into a single string.
2. #define can declare a debugging statement and insert it into the program.
3. #define can declare a sequence of statements to be inserted into the program. If the same code appears in multiple places in the program, the best way is to realize it as a function.

4. The #define macro definition allows parameters to be replaced in the text, #define name(parameter-list) stuff;
1) The parameter-list parameter list is a comma-separated symbol list, the left parenthesis of the parameter list is followed by name, if there is a blank , the argument list will be interpreted as part of the stuff.
2) When the macro is called, the parameters in the parameter list are replaced with stuff, and a pair of parentheses are used for the entire list, and the parentheses need to be correctly added when evaluating the numerical expression to avoid unexpected interactions between operators or adjacent operators in the parameters .

5. Macro parameters and definitions can contain other symbols defined by #define, but macros cannot be recursive. When calling a macro:
1) Check whether the parameters contain other symbols defined by #define, and text replacement is required.
2) The replacement text of the macro definition is inserted into the program, and the parameter value replaces the parameter name.
3) Finally, check the result text to see if it contains the symbols defined by #define, and repeat the above steps.

6. When the preprocessor searches for the symbols defined by #define, it does not check the content of the string constant. If you want to insert macro parameters into the string constant, you can use two techniques: 1) Use the
feature of automatic connection of adjacent strings, insert The string is divided into several sections, and each section is actually a macro parameter, which is used when a string constant is used as a macro parameter.
2) Using the preprocessor to convert macro parameters into string features, the structure #argument is translated into "argument" by the preprocessor, and ## connects the symbols on both sides into one symbol, allowing macro definitions to create identifiers from separate text fragments character, a legal identifier must be produced after concatenation, otherwise the result is undefined.

Macros and functions
1. Simple calculations performed by macros can be implemented with functions.
1) However, the codes of function calls and function returns may be larger than the amount of codes calculated.
2) And function parameters must be declared as a specific type, which can only be used on suitable expressions.
3) Macros are type independent.
4) The code defined by the macro needs to be inserted into the program, which is suitable for relatively short macros, otherwise the program length may be greatly increased.
5) Macros can also be used for functions that cannot be implemented, such as types that cannot be passed as function parameters.

2. Macro parameters with side effects. When a macro parameter appears more than once in a macro definition, if the parameter has side effects, it may be dangerous to use the macro, resulting in unpredictable results, such as x++, which has different results every time it is executed.
3. Parity check is an error detection mechanism. Before data storage and communication, a check bit is added to a value, so that the number of 1s in the binary mode of the data is an even number, and the data can be calculated by calculating the number of 1 bits. Verify the validity, the result is odd, the data is wrong, it is called even parity, and the principle of odd parity is the same.
4. The syntax of using macros is the same as that of functions. In order to distinguish macro definitions from functions, the macro names are all capitalized. When macros use parameters that may have side effects, first store the parameters in temporary variables.
5. The #undef preprocessing directive is used to remove a macro definition. If an existing name needs to be redefined, the old definition needs to be removed with #undef.

6. Command line definition, the compiler allows symbols to be defined on the command line to start the compilation process.
1) When the same source file needs to be compiled in different versions, -Dname=stuff can specify the value of the symbol on the command line. For example, if the program declares an array, a certain machine has limited memory, the array must be smaller, but in another On a machine with sufficient memory, the array can be larger, and the length of the array is specified on the command line when compiling the program.
2) Compilers that provide symbol command lines also provide symbols to be removed from the command line. -Uname ignores the definition of symbol name and is used in conjunction with conditional compilation.
3) The Unix compiler provides -D, -U compilation options.

Conditional compilation
1. When compiling a program, you can choose to ignore a certain statement or a certain group of statements. It is usually used in debugging programs and is not physically deleted from the source code, but it does not appear in the product version of the program. These statements are required for debugging. Conditional compilation accomplishes this by allowing you to choose whether a portion of the code is compiled normally or ignored entirely.
1) #if directive and #endif directive, the constant-expression constant expression in if constant-expression is evaluated by the preprocessor, if the non-zero statements part is compiled normally, otherwise it is ignored.
2) A constant expression is a literal constant or a symbol defined by #define. If the variable cannot obtain a value before execution, the value is unpredictable at the time of compilation, and it is illegal to appear in a constant expression.

2. You can also choose to compile different code parts by #if instruction, #elif instruction, #else instruction, #endif instruction. The number of occurrences of #elif clause is not limited. When all the previous constant expressions are false# else part of the code.
1) #if defined(symbol) = #ifdef symbol to test whether the symbol is defined
2) #if !defined(symbol) = #ifndef symbol
3) The expression is equivalent, but the if form is more powerful, and can be && or ||other expression.
4) The above instructions can be nested to improve code readability. Add a comment tag to each #endif, and the tag content is the expression after #if or #ifdef.

The file contains
1. The #include directive causes the content of another file to be compiled. The preprocessor deletes this directive and replaces it with the content of the included file.
1) If a header file is included in 10 source files, it is actually compiled 10 times.
2) The #include file involves some overhead, but the overhead is small and only exists when the program is compiled. It does not affect the operating efficiency. You don't need to worry about these overheads. The program maintenance is simpler, and you don't need to copy the required source files one by one.
3) Using multiple header files, each header file contains the declaration for a specific function or module, is better than putting all the declarations into one big header file, and the statements in the file will not accidentally access private functions or variables.

2. The compiler supports the inclusion of function library files and local header files.
1) Use angle brackets to include library files and double quotes to include local header files.
2) The local header file includes first searching in all directories of the source file, and then searching for the local header file in the library file path.

3. The standard requires that the compiler must support at least 8 layers of header file nesting, but there is no limit to the maximum nesting value. Too deep nesting will make it difficult to judge the real dependencies between source files.
1) Unix make needs to know the dependencies to determine which files need to be recompiled after the file is modified.
2) And it will cause the same header file to be included multiple times, using conditional compilation, in the header file

#ifndef _HEADERNAME_H 
#define _HEADERNAME_H 
/********************/
#endif

It can solve the problem of multiple inclusions, handle it normally when it is included for the first time, and ignore the content when it is included again.
3) The preprocessor still reads the entire header file. Although the content is ignored, it still slows down the compilation speed, and multiple inclusions should be avoided as much as possible.

Other directives
1, the #error text of error message directive allows error messages to be generated

2. #line number "string" informs the preprocessor that number is the line number entered in the next line, and the optional part of string is used as the name of the current file.
1) The instruction modifies the value of the __LINE__ symbol, and the optional part modifies the value of the __FILE__ symbol.
2) In a program that converts codes in other languages ​​into C codes, use this command to refer errors generated by the C compiler to the source file, rather than the file name and line number of the C intermediate source file generated by the translation program.

3. The #progma directive allows some compilation options. Some compilers use this directive to turn on or off the list display during compilation, or to insert assembly code into a C program, but some compilers do not support this directive. Preprocessing The compiler ignores the #progma directive.
4. #Invalid instruction, a line that starts with # and does not follow any content, the preprocessor deletes the content of the line, which is equivalent to a blank line.

Summary
1. To compile a C program, preprocessing is performed first. Preprocessing supports five symbols.

2. The #define directive associates a symbolic name with an arbitrary sequence of characters.
1) The character sequence may be a literal constant, an expression or a program statement. If the sequence is long, several lines can be separated, and a backslash is added after each line except the last line.
2) The #define directive can be used to rewrite the C language to make it look like other languages.
3) A macro is a defined sequence, and the parameter values ​​are replaced. When the macro is called, each parameter is replaced by a specific value. In order to prevent error expressions related to the macro, each parameter in the macro definition can be Put parentheses on both sides.
4) Macros have nothing to do with types and execute faster than functions, but macros will increase the length of the caller, and parameters with side effects may produce unpredictable results during the use of macros, while the behavior of function parameters is easier to predict.

3. In many compilers, symbols can be defined on the command line, and the #undef directive ignores the definition of symbols.
1) Conditional compilation can create different versions of a program from a single set of source files. The #if directive includes or ignores a sequence of codes according to the results of the test during compilation. When using #elif and #else directives at the same time, you can start from Select one of several sequences of codes to compile and decipher.
2) In addition to testing constant expressions, you can also test whether a certain symbol is defined, and #ifdef and #ifndef directives can also perform this task.

3. The #argument structure is converted into a string constant "argument" by the preprocessor, and ##connects the text on both sides into an identifier.

4. The #include directive is used to implement file inclusion.
1) The file name is enclosed in angle brackets, and the compiler looks for this file in a standard location defined by the compiler, usually used to include library header files.
2) The file name is inside the double quotes, and different compilers use different methods to handle it. If the local file cannot be found, the header file is searched in the standard location, which is usually used for the header file written by oneself.
3) File inclusion can be nested, and nested file inclusion increases the risk of including the same file multiple times, and it is difficult to determine file dependencies.

5. The #error command generates an error message when compiling, and the message contains the selected text.
6. The #line directive specifies the line number and source file name.
7. #progma varies from compiler to compiler. The instruction allows the compiler to provide different processing procedures, such as inserting inline assembly code to a function.

Guess you like

Origin blog.csdn.net/mei_true/article/details/131400050