C language preprocessing and preprocessing

Source: Internet
Author: User

C language preprocessing and preprocessing

This is the last blog in 2016. The plan for the first year is to write 12 blogs, one blog per month, 1/3 reposted, and 2/3 original. It seems that this is impossible! -- Digress. What we want to write today is a pre-processor in C language. We often say macro definition usage. Why do we need to write this? The reason is simple: we didn't know much about preprocessing. If you only know about C language or have studied C language in college, when talking about preprocessing, you only know the following statement: (because I am in this situation, haha !)

1 #define name value

I learned more about preprocessing. The direct driving force is to read the php source code. I started with a macro definer. I had a little bit of 'master' before. # There are too few define methods, I cannot understand the macro processing logic and running path in the source code. So it is necessary to study the Preprocessor again. It is not difficult to learn many things in it, but you are not touched. It is easy to wait for you to learn.

I. Difficulties in macro definition and use

This section describes the code first, so that you can see whether the running results of each code are consistent with your expectation!

What is a macro? The macro is # define mechanism that replaces the specified parameter with the text. This implementation method is macro. Macro definition can be used to extract frequently called functions to speed up execution. Definition: # define name (parameter) execution body... "Parameters" can be a list of parameters separated by commas. These parameters can be applied to the execution body. Note that the Left brackets of "Parameters" must be close to the macro name, otherwise, the editor reports an error or is interpreted as part of the execution body. For example, when you write a TEST (a) a * a Call for execution, the actual execution of TEST (1) is replaced by 1*1.

There are advantages and disadvantages in everything. macro definition is easy to use and has an incomparable execution speed of functions. However, there are many pitfalls in macro definition. Let's talk about this trap. See the following code:

 1 #include <stdio.h> 2  3 #define TEST(a) a * a 4  5 int main() { 6     int b = TEST(2); 7     int c = TEST(1+2); 8     printf("b=%d, c=%d", b, c); 9     printf("\n\n");10 }

What do you think is the result if no execution is performed! A lot of people say without thinking: B = 4, c = 9. If this is the case, there will be no pitfall. The actual output is: B = 4, c = 5. Why is there a deviation between the value of c and the Expected One, in fact, if you try to replace the value in the execution body, it is not difficult to find the problem. When you enter 1 + 2, the macro is replaced with 1 + 2*1 + 2, of course it is 5. Okay, you understand. Have you learned? I learned to look at another one:

 1 #include <stdio.h> 2  3 #define TEST(a,b) ((a) > (b) ? (a) : (b)) 4  5 int main() { 6     int zyf = 1; 7     int abc = 2; 8     int ret = TEST(zyf++, abc++); 9     printf("zyf=%d,abc=%d,ret=%d", zyf, abc, ret);10     printf("\n\n");11 }

If zyf = 2, abc = 3, ret = 3, the result is: zyf = 2, abc = 4, ret = 3. The truth is the same as the previous one. Only the replaced result can be used to see the answer.

The solution is simple. The cause of the error is that the execution sequence is different from what we expected. Then, parentheses should be added to solve this problem. For example, (a) * (). This is actually not the most comprehensive method. For example, if you look at this: ADD (a) + (a), if you call: ADD (2) * 5, this is not the case. It is replaced with (a) + (a) * 5. The execution sequence is different from the expectation. Therefore, we need to add parentheses on the outermost layer: () + (.

 

  IIPre-defined symbols

There are several predefined symbols in the C language. It is still necessary to talk about it first. Let's take a look at the Code:

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #define VAR_DUMP printf( \ 4     "[\n \tfile:%s\n" \ 5     "\tline:%d\n" \ 6     "\ttime:%s %s\n" \ 7     "\tvalue:%d\n]", \ 8     __FILE__, __LINE__, __DATE__, __TIME__, value \ 9 )10 int main() {11     int value = 1;12     VAR_DUMP;13     printf("\n\n");14 }

Is it a little different from what you learned in college? The simplest macro definition can use the # define name value method. Of course, you can also write the value as a function and replace the function directly during running. This macro definition encapsulates the debugging method, which is to print the content of the variable like the var_dump () or print_r () function in PHP.

You can learn the following points from this Code:

1. Use # define to replace any text in the program. In the main program, you can use VAR_DUMP at will.

2. The macro definition does not end with a semicolon. If the macro definition is very long, you can add a backslash to the end to separate the macro to keep the code easy to understand.

3. You can define a function that is frequently called as a macro to accelerate the execution speed. The specific reason will be discussed later.

4. There are several predefined symbols in the C language that we need to know. It is especially useful in many cases:

_ FILE _ pre-compiled FILE name

_ LINE _ the row number of the current row of the file (execute to this row)

_ DATE of file Compilation

_ TIME _ specific TIME of file Compilation

_ STDC _ whether to follow ansi c (not commonly used)

Finally, attach the running result,

  3.Macro Replacement Process

In the compilation phase of a program, the macro is replaced by an execution, which generally involves the following steps:

1. Check whether the macro is defined # define. If yes, replace it.

2. Insert the replaced text information to the replacement location, and replace the parameter with the actual value.

3. # define can contain other defined # define definitions. Note that recursion is not allowed.

Because there is an automatic combination of adjacent fields in replacement, some clever solutions can be used:

 1 #include <stdio.h> 2 #include <stdlib.h> 3  4 #define VAR_DUMP(A,B)\ 5    printf("Value of " #B " is " A "\n", B) 6  7 int main(){ 8     int x = 1; 9     VAR_DUMP("%d", x+2);10 }

  

  ThuConditional compilation and other macro usage

In large C Programs, you can see a lot of Conditional compilation. For example, you can load different macro configurations according to the current environment, or add the pre-compiled conditions of the direct pole during compilation. The implementation of these things is inseparable from Conditional compilation.

1. Conditional nesting, # if # endif prototype:

1 # if condition2 execution body 3 # endif

You can determine whether or not the execution body is executed Based on the condition to control the compilation into different systems in different environments. See the following code. When debugging is defined as a non-zero value, the MAX macro definition exists. When it is defined as 0, an error is reported.

 1 #include <stdio.h> 2  3 #define DEBUG 0 4 #if DEBUG 5     #define MAX(a) ((a) * (a)) 6 #endif 7  8 int main() { 9     int b = MAX(2);10     int c = MAX(1+2);11     printf("b=%d, c=%d", b, c);12     printf("\n\n");13 }

Of course, # if can also be used with # elif nesting, which is the same as using if else in the function. Below is a section of the php source code, you can see that php compilation can specify different parameters, check different environments, and so on, all of which can be completed through Conditional compilation in preprocessing.

 1 #ifndef PHP_H 2     #define PHP_H 3  4     #ifdef HAVE_DMALLOC 5         #include <dmalloc.h> 6     #endif 7  8     #define PHP_API_VERSION 20100412 9     #define PHP_HAVE_STREAMS10     #define YYDEBUG 011 12     #include "php_version.h"13     #include "zend.h"14     #include "zend_qsort.h"15     #include "php_compat.h"16     #include "zend_API.h"17 18     #undef sprintf19     #define sprintf php_sprintf20 21     /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */22     #undef PHP_DEBUG23     #define PHP_DEBUG ZEND_DEBUG24 25     #ifdef PHP_WIN3226     #    include "tsrm_win32.h"27     #    include "win95nt.h"28     #    ifdef PHP_EXPORTS29     #        define PHPAPI __declspec(dllexport)30     #    else31     #        define PHPAPI __declspec(dllimport)32     #    endif33     #    define PHP_DIR_SEPARATOR '\\'34     #    define PHP_EOL "\r\n"35     #else36     #    if defined(__GNUC__) && __GNUC__ >= 437     #        define PHPAPI __attribute__ ((visibility("default")))38     #    else39     #        define PHPAPI40     #    endif41 42     #    define THREAD_LS43     #    define PHP_DIR_SEPARATOR '/'44     #    define PHP_EOL "\n"45     #endif46 47     #ifdef NETWARE48         /* For php_get_uname() function */49         #define PHP_UNAME  "NetWare"50         #define PHP_OS      PHP_UNAME51     #endif52 53     #if HAVE_ASSERT_H54         #if PHP_DEBUG55             #undef NDEBUG56         #else57             #ifndef NDEBUG58                 #define NDEBUG59             #endif60         #endif61         #include <assert.h>62 63     #else /* HAVE_ASSERT_H */64         #define assert(expr) ((void) (0))65     #endif /* HAVE_ASSERT_H */66 67     #define APACHE 068     #if HAVE_UNIX_H69         #include <unix.h>70     #endif71 72     #if HAVE_ALLOCA_H73         #include <alloca.h>74     #endif75 76     #if HAVE_BUILD_DEFS_H77         #include <build-defs.h>78     #endif79     . . . 

2. Whether it has been defined

Defined: # if define () or # ifdef

Not Defined: # if! Define () or # ifndef

Although the former is not refined, the former has more use cases, such as the following, which can be nested.

1 #if defined(DEBUG)2      #ifdef DEBUGTWO3            #define TEST(a) a * a4      #endif5 #endif

3. Remove a macro definition. When a macro definition is no longer used, you can use undef to remove unnecessary macros. prototype:

1 #undef name

 

  V.Macro naming rules and differences with functions

From the previous usage, we can see that the usage rules of macros are exactly the same as those of functions, but they are essentially different. How can we differentiate macros and functions in use, it involves code specifications and code readability issues. The standard macro should use uppercase letters, so that any macro in the program will know that this is a macro definition. For example, the previous # define TEST (a) * ()).

The differences between macros and functions are as follows:

1. In terms of execution speed, macro definition is faster. Because the function needs to call stacks, there are calls, returns, and saves the overhead of the on-site system, so it is slower than macro.

2. In terms of code length, macros actually increase in code length. Every macro replaces the name with macro content. If a large number of macro content is used, the Code increases significantly, function Code only has one copy, saving code space.

3. For the parameter type, the macro does not have a parameter type, as long as it can be used. Different functions have different parameter types. Because of this, some macros can skillfully use this to complete tasks that cannot be completed by functions. Read the following code (read in the book ), use the unrestricted transmission type to automatically open up various types of space:

1 #include <stdio.h>2 #include <stdlib.h>3 4 #define CREATE_P(nums, type) ((type *) malloc((nums) * sizeof(type)))5 6 int main(){7     int nums = 2;8     CREATE_P(nums, int);9 }

4. macro definition and function use scenarios. macro definition is generally at the beginning of a program. to convert a function into a macro definition, you must consider the cost. Short and refined functions are the best to convert them into macros, converting a function to a macro is not worth the candle.

 

  Sat., File inclusion

  1. Local file inclusion and Library File Inclusion

The file package must be used in a large system. The macro definition of a large system is huge, and it is impossible to copy all macro definitions to each file. Therefore, file inclusion can solve this problem.

In fact, the editor supports two types of file inclusion. One is the inclusion of library files that we often use, as we can see above: # include <stdio. h>, there is also a local file inclusion. To put it bluntly, we write our own files. The prototype is as follows:

1 #include <filename>2 #include "filename"

Both methods can be used to include files. The difference is that the first method is to include library files, and the Standard C library functions will always use. the end of the h extension, and the second is local file inclusion. When the editor sees the second method, the local library file obtained in this path is preferentially searched, if it is not found, it will be searched in the specified path as it contains the library file. In this case, the second type is similar to the first one. The second inclusion method is also good in coding habits. It is easy for others to see whether the file is a library function or written by yourself.

  1. nested file inclusion

A large system not only contains a large number of files, but also contains a large number of nested files. See the following example:

A. h, B. h, c. h, define. c files. The contents of a, B, c, and define files are as follows:

 1 a.h: 2 #include "c.h" 3 void var_dumpa(){ 4     test obja; 5     obja.a[1] = 2; 6     printf("obja.a[1]: %d\n", obja.a[1]); 7 } 8  9 b.h:10 #include "c.h"11 void var_dumpb(){12     test objb;13     objb.a[1] = 2;14     printf("objb.a[1]: %d\n", objb.a[1]);15 }16 17 c.h:18 #include <stdlib.h>19 #include <stdio.h>20 21 typedef struct test{22     int a[10];23 }test;24 25 define.c:26 #include <stdio.h>27 #include "a.h"28 #include "b.h"29 30 int main() {31     var_dumpa();32     var_dumpb();33     printf("\n\n");34 }

The AB file contains the c file, define. when file a and file B are referenced in file c, an error occurs: typedef struct test type error. the H file is contained twice, which is often encountered in large systems like this, or you will find that duplicate reference library files do not report errors, the library file must have a solution. In fact, the solution to this error is Conditional compilation. When this file is introduced to another file, we can set a macro definition, such:

1 #include <stdlib.h>2 #include <stdio.h>3 4 #ifndef PATH_C_H5     #define PATH_C_H 16     typedef struct test{7         int a[10];8     }test;9 #endif

This is because the compiler will read the entire header file every time it compiles. If this condition is added to all the files, the problem of repeated macro compilation generated by the cross-reference file will be solved. The operation is as follows:

Well, let's write so much about it and repeat our understanding of macro definition and basic usage. The time was too short. Please point out something wrong. Thank you very much!

Note: 1, this blog synchronously updated to my personal website: http://www.zhaoyafei. cn2, this article is original content, in order to respect others' work, reprint please note this article address:

Http://www.cnblogs.com/zyf-zhaoyafei/p/6237295.html

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.