(1) Basic knowledge
Preprocessor indicators start with "#". Programs that process these indicators are called preprocessors.
# The include indicator reads the content of a specified file in two formats:
# Include <some_file.h>
# Include "my_file.h"
If the file name is enclosed by <>, it indicates that the file is a project or standard header file. The search process first checks the pre-defined directory.
You can modify these directories by setting environment variables or command lines. If the file name is caused by "", it indicates that the file is provided by the user.
Header file, which starts from the directory where the current file is located.
Due to the nesting relationship of header files, a header file may be contained again. The condition indicator prevents repeated processing of such header files. For example
For example:
# Ifndef bookstore_h
# Define bookstore_h
// Content of bookstore. h
# Endif
# Ifndef indicates what to do if a macro is not defined
# Ifdef indicates what to do if a macro has been defined.
For example:
Int main (){
# Ifdef debug
Cout <"begining execution of main/N ";
# Endif
String word = "Hello world! ";
Cout <world <Endl;
}
In this example, If debug is not defined, the actual compiled code is as follows:
Int main (){
String word = "Hello world! ";
Cout <world <Endl;
}
If debug has been defined, the program code passed to the compiler is:
Int main (){
Cout <"begining execution of main/N ";
String word = "Hello world! ";
Cout <world <Endl;
}
We can use the-D option when compiling the program, and write the Preprocessor constant name later, so that we can define the Preprocessor in the command line.
Processors often:
$ CC-ddebug main. c
You can also use the # define indicator in the program to define the Preprocessor constant.
(2) automatically defined Preprocessor name
When compiling a C ++ program, the compiler automatically defines a Preprocessor name _ cplusplus (the first two underscores ). Therefore, we can
To determine whether the program is a C ++ program based on it, so as to include some code with conditions. For example
# Ifdef _ cplusplus
Extern "C"
# Endif
Int min (INT, INT );
When compiling standard C, the compiler automatically defines _ stdc __.
Some other commonly used predefined names are:
_ Line _: number of lines compiled by the file
_ File _: name of the compiled file
_ Time _: Current Compilation Time of the compiled file
_ Date _: current compilation date of the compiled file
In addition, c99 adds _ FUNC _ to indicate the name of the compiled function. For GCC, the name equivalent to _ FUNC _ is
_ Function __.
The predefined names are helpful for trace writing, for example:
If (I = 0)
Cerr <"error:" <__file __< <": line:" <__line <": func "<__ func __< <" I must be non-zero/N ";
(3) C and C ++ header files
The C ++ name of the C library file always starts with the letter C, followed by the c Name that removes the suffix. H, such as assert (): If the C ++ header file is used
If it is cassert and C is assert. H, the C name or C ++ name of the header file is used, and the methods are also different. Take assert as an example:
C ++: # include <cassert>
Using namespace STD;
C: # include <assert. h>
(4) macro replacement
The macro replacement process was never described in detail before Iso c. This ambiguity leads to many different implementations. Dependent on obvious Constants
Any code that replaces the more exotic things with simple class function macros may not be truly portable. In addition, the iso c macro replacement algorithm can be completed in the old
Tasks that cannot be completed in C. For example:
# Define name (* name)
Replace any use of name with indirect reference by name. The old c Preprocessing Program will generate a large number
Parentheses and star numbers, and ultimately generate macro recursion errors.
The main change of the macro replacement method in iso c requires macro parameters, rather than macro replacement operators # And #.
Replace the parameters that need to be extended recursively in the replace tag list. However, this change rarely produces actual differences in the result tag.
For example, use the # macro replacement operator and string text
# Define STR (a) # "! "
STR (x y)
The above code generates two strings: "x y" and "! ", They generate the same" x y! "
For macros with variable parameters, the same processing method of gnuc and Sun CC is as follows:
# Define identifier (...) replacement_list
# Define identifier (identifier_list,...) replacement_list
If the listed macro parameters end with a ellipsis, more macro parameters except macro parameters can be called. Additional Parameters
Collected in a separate string, which can contain commas. You can use the macro to replace the name _ va_args _ in the list.
Use these additional parameters (replacement_list variable parameters are replaced by _ va_args ).
For gnu c, there is another way to use # ARGs For reference (replacement_list's variable parameter is # ARGs),
The definition method of the object is also different:
# Define identifier (ARGs...) replacement_list
# Define identifier (identifier_list, argS...) replacement_list
(5) usage of "#" and "#" in macro
I. general usage
We use # to convert the macro parameter into a string, and # to combine the two macro parameters.
Usage:
# Include <cstdio>
# Include <climits>
Using namespace STD;
# Define STR (s) # s
# Define cons (a, B) int (A ## e ## B)
Int main ()
{
Printf (STR (vck); // output string "vck"
Printf ("% d/N", cons (2000); // 2e3 output:
Return 0;
}
Ii. When the macro parameter is another macro
It should be noted that all macro parameters that use '#' or '#' in macro definition will not be expanded.
1. Non-'#' and '#'
# Define tow (2)
# Define MUL (a, B) (a * B)
Printf ("% d * % d = % d/N", tow, tow, MUL (tow, tow ));
The Macros in this line will be expanded:
Printf ("% d * % d = % d/N", (2), (2), (2) * (2 )));
The tow parameter in Mul is expanded to (2 ).
2. When '#' or '#' is available
# Define a (2)
# Define STR (s) # s
# Define cons (a, B) int (A ## e ## B)
Printf ("int MAX: % s/n", STR (int_max); // int_max # I nclude <climits>
This row is expanded:
Printf ("int MAX: % s/n", "int_max ");
Printf ("% s/n", cons (A, A); // compile Error
This line is:
Printf ("% s/n", INT (AEA ));
Int_max and a will not be expanded. However, the solution to this problem is simple. add another layer of intermediate conversion macro.
The purpose of adding this macro layer is to expand all macro parameters in this layer, so that the macro (_ Str) in the conversion macro can get the correct macro.
Parameters.
# Define a (2)
# DEFINE _ STR (s) # s
# Define STR (s) _ STR (s) // convert macro
# DEFINE _ cons (a, B) int (A ## e ## B)
# Define cons (a, B) _ cons (a, B) // convert a macro
Printf ("int MAX: % s/n", STR (int_max); // The maximum value of int_max, int type, is a variable
# Include <climits>
Output: int MAX: 0x7fffffff
STR (int_max) --> _ STR (0x7fffffff) and then convert it to a string;
Printf ("% d/N", cons (A, ));
Output: 200
Cons (a, a) --> _ cons (2), (2) --> int (2) E (2 ))
Iii. Application exceptions of '#' and '#'
1. Merge anonymous variable names
# Define ___ anonymous1 (type, VAR, line) type var # Line
# DEFINE _ anonymous0 (type, line) ___ anonymous1 (type, _ anonymous, line)
# Define anonymous (type) _ anonymous0 (type, _ line __)
For example, anonymous (static INT); that is, static int _ anonymous70; 70 indicates the row number;
First layer: anonymous (static INT); --> _ anonymous0 (static int, _ line __);
Layer 2: --> ___ anonymous1 (static int, _ anonymous, 70 );
Layer 3: --> static int _ anonymous70;
That is, the macro of the current layer can only be unlocked at each time, so _ line _ can be unlocked at the second layer;
2. fill Structure
# Define fill (a) {A, #}
Enum IDD {open, close };
Typedef struct MSG {
Idd id;
Const char * MSG;
} MSG;
MSG _ MSG [] = {fill (open), fill (close )};
Equivalent:
MSG _ MSG [] = {open, "open "},
{Close, "close "}};
3. Record File Name
# DEFINE _ get_file_name (f) # F
# Define get_file_name (f) _ get_file_name (f)
Static char file_name [] = get_file_name (_ file __);
4. Obtain the buffer size of the string corresponding to the value type.
# DEFINE _ type_buf_size (type) sizeof # type
# Define type_buf_size (type) _ type_buf_size (type)
Char Buf [type_buf_size (int_max)];
--> Char Buf [_ type_buf_size (0x7fffffff)];
--> Char Buf [sizeof "0x7fffffff"];
This is equivalent:
Char Buf [11];