Compilation preprocessing is the initial step in the process of converting a C source program into an executable program. This step is done by the preprocessor (preprocessor). Before the source program is processed by the compiler, the preprocessor first processes the macro (macro) in the original program.
C Beginners may have no concept of preprocessor, this is understandable: the General C compiler will be preprocessed, assembly, compilation, connection process integration. Compilation preprocessing often runs in the background. In some C compilers, these processes are all performed by a single program, and the different stages of compilation implement these different functions. You can specify the appropriate command options to perform these functions. Some c compilers use separate programs to complete these steps. These programs can be called individually to complete. In GCC, the program for compiling preprocessing is called CPP, and its executable file name is CPP.
The syntax of the compilation preprocessing command is completely independent of the syntax of the C language. For example, you can extend a macro to something that is out of tune with the C syntax, but the content is combined with the following statement in a form that generates a valid C statement that can be compiled correctly.
(i) Introduction to preprocessing commands
The preprocessing command starts with a # (hash character) that is exclusive to one line, #之前只能是空白符. The statement that begins with # is the preprocessing command, and the statement that does not begin with # is the line of code in C. The common preprocessing commands are as follows:
#define Define a preprocessing macro #undef to cancel the definition of a macro
#include include file commands #include_next is similar to #include, but it has a special purpose.
#if the Conditional command in the compilation preprocessing, equivalent to the IF statement in C syntax #ifdef Determine whether a macro is defined, and if so, execute the following statement #ifndef, contrary to #ifdef, determines whether a macro has not been defined #elif if the #if, #ifdef, #ifndef或前面的 #elif conditions are not satisfied, then execute the statement after #elif, equivalent to the else-if in C syntax #else and #if, #ifdef, #ifndef对应, if these conditions are not satisfied, then execute the statement after #else, equivalent to the else in C syntax #endif #if, #ifdef, #ifndef这些条件命令的结束标志. Defined and #if, #elif配合使用, to determine whether a macro is defined
#line flag the line number where the statement is located # Replace macro arguments with character-channeling constants with parameter values as content # # Connect two adjacent tags (token) to a single tag #pragma description Compiler information
#warning Display compilation Warning information #error Display compilation error messages
(ii) pretreatment of grammars
Preprocessing does not parse the entire source code file, it simply divides the source code into some tags (token), identifies which of the statements are C statements, and which are preprocessing statements. The preprocessor can recognize C tags, file names, whitespace characters, and file end flags.
Preprocessing statement format: #command name (...) token (s)
1, the name of the command preprocessing order, which preceded it with a #, #之后紧随预处理命令, standard C allows for whitespace on either side, but older compilers may not allow this. If a row contains only # (and whitespace), then the line in standard C is interpreted as blank. The entire preprocessing statement can be followed by only whitespace characters or annotations, and no other content. 2, name represents the macro name, which can take parameters. The parameter can be a variable argument list (C99). 3, you can use "\" in the statement to wrap the line.
e.g. # define one 1/* one = 1 * Equivalent to: #define ONE 1
#define ERR (flag, MSG) if (flag) \ printf (msg) Equivalent to: #define ERR (flag, MSG) if (flag) printf (msg)
(iii) detailed preprocessing orders
1, #define #define命令定义一个宏: #define MACRO_NAME (args) tokens (opt) The macro_name that appear later will be substituted for the defined tag (tokens). Macros can take parameters, and the following tags are optional.
Object macros Macros with no parameters are called "Object macros (Objectlike macro)"
#define经常用来定义常量, the macro name is typically an uppercase string. This facilitates the modification of these constants. e.g. #define MAX 100 int A[max];
#ifndef __file_h__ #define __file_h__ #include "file.h" #endif The macros in the #define __FILE_H__ do not take any arguments, nor do they extend to any tags. This is often used to include header files.
To invoke the macro, simply specify the macro name in your code, and the macro will be substituted for what it is defined for.
function macros Macros with parameters are also referred to as "function macros." The use of macros can improve the efficiency of the code: subroutine calls need to stack out of the stack, this process if too often consumes a lot of CPU computing resources. So some code small but frequently run code if with parameter macros to achieve will improve the efficiency of the Code.
The parameter of the function macro is a fixed condition
function macros are defined in such a way that #define name (args) tokens The args and tokens are optional. It differs from the object macro definition in that the macro name is not followed by parentheses.
Note that the opening parenthesis after name, which must be immediately followed by name, cannot have spaces between them, otherwise this defines an object macro that will be replaced with the (starting string). But when calling a function macro, name and (can have spaces between).
e.g. #define MUL (X,y) ((x) * (y))
Notice that the arguments after the function macro are enclosed in parentheses to see this example: e.g. #define MUL (X,y) x*y "Mul (1, 2+2);" will be expanded to: 1*2 + 2 Also, the entire tag string should be quoted in parentheses: e.g. #define MUL (X,y) (x) * (y) sizeof Mul (1,2.0) will be extended to sizeof 1 * 2.0
When calling a function macro, the argument passed to it can be either the return value of the function or any meaningful statement: e.g. Mul (f (a,b), G (c,d));
e.g. #define INSERT (stmt) stmt Insert (a=1; b=2;) The equivalent of adding a=1 to the code; b=2. Insert (a=1, b=2;) There is a problem: the preprocessor prompts for an error: The number of parameters for the function macro does not match. The preprocessor Treats "," as a separator between parameters. Inserts (A=1, b=2;) can solve the above problems.
When defining and invoking function macros, there are some issues to be aware of: 1, we often use {} to refer to the content defined by the function macro, which should be paid attention to when calling the function macro ";" Problem. example_3.7: #define SWAP (x,y) {unsigned long _temp=x; x=y; y=_tmp} If you call it this way: "Swap (1,2);" will be extended to: {unsigned long _temp=1; 1=2; 2=_tmp}; Obviously behind; it's superfluous, we should call it this way: Swap (1,2) Although such a call is correct, it contradicts the C syntax, and you can use the following method to handle the content enclosed by {}:
#define SWAP (x,y) \ Do {unsigned long _temp=x x=y y=_tmp} while (0) Swap (1,2); will be replaced by: Do {unsigned long _temp=1, 1=2 2=_tmp} while (0); This do-while (0) statement is widely used in the Linux kernel source code.
2, some function macros can not be implemented with Do-while (0), so the call can not be brought on the ";", it is best to add a comment after the call description. eg_3.8: #define INCR (V, low, high) \ for ((v) = (low); (v) <= (high); (v) + +) Can only be called in this form: incr (A, 1,)/* Increase a Form 1 to 10 * *
A parameter in a function macro includes a variable argument list The contents of the variable parameter list are added to the C99 standard. Not just functions, you can also use a variable argument list in a function macro.
#define NAME (args, ...) tokens #define NAME (...) tokens "..." represents a variable argument list, and if it is not the only argument, it can only appear at the end of the argument list. When you call such a function macro, the number of arguments passed to it is not less than the number of arguments in the argument list (extra arguments are discarded). Replace the variable argument list in the function macro with __va_args__. Note that __va_args__ can only be used in functions where the parameters in the function macro contain "...".
e.g. #ifdef DEBUG #define MY_PRINTF (...) fprintf (stderr, __va_args__) #else #define MY_PRINTF (...) printf (__va_args__) #endif
The __va_args__ in tokens is replaced by the "..." variable argument list in the function macro definition.
Note Some common errors when using #define: #define MAX = 100 #define MAX 100; =, ; Should be noted for its use. Then the call function macro is to pay attention, do not give more ";"
Note: Function macros are insensitive to parameter types, and you do not have to consider what data types to pass to macros. So how do you build a macro that is sensitive to parameter types? Refer to the Nineth part of this chapter for an introduction to "# #". |
some other questions about defining macros (1) Macros can be defined multiple times, provided that the definitions must be the same. The "Same" here requires that the whitespace appear in the same position, but the specific whitespace type or number can be different, such as the original space can be replaced by several other types of white space characters: can be tab, note ... e.g. #define NULL 0 #define NULL/* NULL pointer * * 0 The redefinition above is the same, but the following definitions are different: #define FUN (x) x+1 #define FUN (x) x + 1 or: #define Fun (y) y+1 If the content of the macro is redefined differently when it is defined more than once, GCC gives the "NAME redefined" warning message.
You should avoid redefining function macros, whether in a preprocessing command or in a C statement, preferably with a single definition of an object. In GCC, GCC gives a warning if a macro appears to be redefined.
(2) in GCC, you can specify the definition of an Object macro on the command line: e.g. $ gcc-wall-dmax=100-o tmp tmp.c The equivalent of adding "#define MAX 100" to the TMP.C.
So what happens if the original tmp.c contains the definition of the max macro and then uses-dmax in the GCC invocation command? ---if-dmax=1, compile correctly. ---If the value of-dmax is specified as a value that is not 1, then GCC gives a warning that the Max macro was redefined, and Max's value is still 1.
Note: If the value of an object macro is not shown in the command line that calls GCC, then GCC gives the macro a default value (1), such as:-dval = =-dval=1
(3) #define所定义的宏的作用域 The macro does not take effect until it is defined, and if the macro definition is #undef canceled, the macro is #undef. and the macros in the string are not recognized e.g. #define ONE 1 sum = one + two/* sum = 1 + two * * #define TWO 2 sum = one + two/* sum = 1 + 2 * * #undef One sum = one + two/* sum = one + 2 * *
Char c[] = "Two"/* c[] = "Two", not "2"! */
(4) Macros can be replaced recursively, so you can nest definition macros. e.g. # define one number_1 # define NUMBER_1 1 int a = one/* A = 1 * *
2, #undef #undef用来取消宏定义, it is opposed to the #define: #undef Name If a macro that is canceled is actually not defined by #define, the #undef against it does not produce an error. Once a macro definition is canceled, it can be defined again.
3, #if, #elif, #else, #endif #if, #elif, #else, #endif用于条件编译:
#if constant Expression 1 Statement... #elif constant Expression 2 Statement... #elif constant Expression 3 Statement... ... #else Statement... #endif
#if和 #else is equivalent to if, else in the C statement respectively. They determine whether to execute subsequent statements based on the value of a constant expression. #elif相当于C中的else-if. Using these conditions to compile commands facilitates the control of source code content. else is not followed by a constant expression, but if a constant expression is included, GCC simply gives a warning message.
Use them to improve the portability of your code---execute different statements for different platforms. is often used for large code comments. e.g. #if 0 { A large section of code; } #endif
A constant expression can be a valid C-constant expression that contains macros, arithmetic operations, logical operations, and so on, and its value is treated as 0 if the constant expression is an undefined macro. #if macro_non_defined = = #if 0 When deciding whether a macro is defined, you should avoid using #if, because the value of the macro may be defined as 0. Instead, use the #ifdef or #ifndef described below.
Note: #if, #elif, #else之后的宏只能是对象宏. If the macro name is not defined, or the macro is a function macro. Then using the "-wundef" option in GCC displays a warning message that is not defined by the macro.
4, #ifdef, #ifndef, defined. #ifdef, #ifndef, defined is used to test whether a macro is defined #ifdef name or #ifndef name
They are often used to avoid duplicate references to header files: #ifndef __file_h__ #define __file_h__ #include "file.h" #endif
Defined (name): Johong is defined, returns 1, otherwise returns 0. It #elif with #if, #else结合使用来判断宏是否被定义, at first glance as if it seemed superfluous, for there had been #ifdef and #ifndef. Defined is used to declare multiple discriminant conditions in a single judgment statement:
#if defined (VAX) && defined (UNIX) &&!defined (DEBUG)
And #if, #elif, #else不同, #indef, #ifndef, the defined test macro can be an object macro, or it can be a function macro. Using the "-wundef" option in GCC does not display warning messages that are not defined by macros.
5, #include, #include_next #include用于文件包含. The line on which the #include command is located cannot contain anything other than comments and whitespace characters. #include "Headfile" #include #include preprocessing token All of the previous two forms are familiar to you, in the #include preprocessing tag, the preprocessing tokens are replaced by the preprocessor, and the resulting replacement must conform to one of the first two forms.
In fact, the header file that is actually added is not necessarily the file specified in #include. #include "Headfile" contains header files of course the same file, but the #include For more information about the difference between #include "headfile" and #include Compared to #include, we are not familiar with #include_next. #include_next仅用于特殊的场合. It is used in header files (#include既可用于头文件中, and can be used in. c files) to contain additional header files. And the path that contains the header file is special: the header file is searched from the directory behind the directory where the current header file resides. For example: The header file's search path is once a,b,c,d,e. #include_next所在的当前头文件位于B目录, then #include_next enables the preprocessor to search the C,d,e directory for the header file specified by #include_next.
Refer to CPP Manual for further understanding of #include_next
6, predefined macros Standard C defines some object macros whose names begin and end with "__" and are all uppercase characters. These predefined macros can be #undef or redefined.
Some of the predefined object macros that are common in standard C are listed below, which also contain some of the scheduled Yi Hong that GCC has defined itself: __line__ the line number in which the current statement is located, annotated with a 10 integer. __file__ the file name of the current source file, annotated with a string constant. __DATE__ the date the program was compiled in a string callout in the format "MMM DD yyyy". The time the __TIME__ program is compiled, in a string callout in "HH:MM:SS" format, which is returned by Asctime.
__stdc__ if the current compiler complies with the ISO standard, the value of this macro is 1 __stdc_version__ if the current compiler conforms to C89, it is defined as 199409L and, if C99, is defined as 199901L. I use GCC, if I do not specify-STD=C99, other cases give __stdc_version__ undefined error message, what's the problem? __stdc_hosted__ if the current system is "Local System (hosted)", then it is defined as 1. The local system indicates that the current system has a complete standard C library.
The scheduled Yi Hong defined by GCC: __optmize__ if optimizations are used during compilation, the macro is defined as 1. __optmize_size__ Ibid, but is defined as 1 only when optimization is for code size rather than speed. __VERSION__ Displays the version number of the GCC used. Refer to "GCC the complete Reference". To see all of the predefined macros defined by GCC, you can run: $ cpp-dm/dev/null
7, #line #line用来修改__LINE__和__FILE__. e.g. printf ("Line:%d, File:%s\n", __line__, __file__); #line "haha" printf ("Line:%d, File:%s\n", __line__, __file__); printf ("Line:%d, File:%s\n", __line__, __file__);
Show: Line:34, file:1.c LINE:100, File:haha LINE:101, File:haha
8, #pragma, _pragma #pragma用编译器用来添加新的预处理功能或者显示一些编译信息. #pragma的格式是各编译器特定的, GCC is as follows: #pragma GCC name Token (s)
#pragma之后有两个部分: gcc and the specific pragma name. The following are commonly used in GCC.
(1) #pragma GCC dependency Dependency tests the timestamp of the current file (both the program code in which the statement is located) and the specified file (both the file listed in the #pragma statement). If the specified file is newer than the current file, a warning message is given. e.g. In the DEMO.C, this sentence is given: #pragma GCC dependency "Temp-file" Then create an updated file in the directory where DEMO.C is located: $ touch Temp-file, compiling: $ gcc demo.c gives such a warning message: Warning:current file is older than If the current file is newer than the specified file, no warning message is given.
You can also add a custom warning message in #pragma. e.g. #pragma GCC dependency "temp-file" "demo.c needs to be updated!" 1.c:27:38:warning:extra tokens at the end of #pragma directive 1.c:27:38:warning:current file is older than Temp-file Note: The next additional warning message will be referenced by "", or GCC will give a warning message.
(2) #pragma GCC poison token (s) If the token (s) in the #pragma is present in the source code, a warning message is displayed at compile time. It is generally used to give an error message when calling a function that you do not want to use. e.g. #pragma GCC Poison scanf scanf ("%d", &a); Warning:extra tokens at the end of #pragma directive Error:attempt to use poisoned "scanf" Note that if the token given in poison is invoked, the compiler will give an error message. As for the first warning, I do not know how to avoid it, and use the token (s) to refer to it.
(3) #pragma GCC System_header The code from #pragma GCC System_header until the end of the file is considered by the compiler as code in the system header file. The code in the system header file is often not fully compliant with the C standard, so the warning message in the header file is often not displayed. (except with #warning显式指明). (This #pragma statement has not found any significant use)
Because #pragma cannot be extended with macro, GCC also provides_pragma: e.g. #define PRAGMA_DEP #pragma GCC dependency "Temp-file" Since preprocessing makes a macro extension, using the above method raises an error at compile time, to define a #pragma statement as a macro extension, you should use the following _PRAGMA statement: #define PRAGMA_DEP _pragma ("GCC dependency \ temp-file\") Note that the "" reference contained in () should be preceded by the \ Escape character.
9, #, # # #和 # #用于对字符串的预处理操作, so they are often used in string display functions such as printf, puts, and so on. #用于在宏扩展之后将tokens转换为以tokens为内容的字符串常量. e.g. #define TEST (a,b) printf (#a "<" #b "=%d\n", (a) < (b)); NOTE: #只针对紧随其后的token有效! # #用于将它前后的两个token组合在一起转换成以这两个token为内容的字符串常量. Note # #前后必须要有token. e.g. #define TYPE (type, n) type N
Called after: TYPE (int, a) = 1; TYPE (long, b) = 1999; will be replaced by: int a = 1; Long B = 1999;
(a) #warning, #error #warning, #error分别用于在编译时显示警告和错误信息, the format is as follows: #warning Tokens #error tokens e.g. #warning "some warning" Note that after the #error和 #warning token to use "" Quote! (in GCC, if a warning is given, the compilation continues, but if an error is given, the compilation stops.) If-werror is specified on the command line, it is not compiled, even if there is only a warning message. |