Preprocessing of the secrets in C Language

Source: Internet
Author: User

Preprocessing is an important knowledge point of C language. It can improve the programming environment and help to write programs that are easy to transplant and debug. Therefore, it is necessary for us to master the pre-processing command and use it flexibly during our own programming, so that the program structure is excellent and easier to debug and read. Next, I try my best to explain the important knowledge points in Preprocessing to readers so that they can skillfully use preprocessing commands in their future programming processes.

C language preprocessing has three main aspects:

1. File Inclusion

2. macro definition

3. Conditional compilation

1. There are two types of File Inclusion:

1. # include "file name"

2. # include <File Name>

The difference between them is: <File Name> the system searches for files in the header file directory, and "file name" searches for files in the current directory first. If no file name is found in the header file directory; of course, you can also use the command line to specify the path of the header file. Note that if a call occurs between the header files contained in the source file, the called header file must appear before the called header file.

Ii. macro definition

A macro can be defined in two forms: one without parameters and the other with parameters.

1. Without Parameters

Format: # define identifier string

I believe that the above format is no stranger to everyone. Let's take a look at how to use it. Of course, let's take a look at the following points of attention during use:

(1) pre-processing does not perform syntax check, so we should be especially careful when selecting

(2) The macro definition is written outside the curly braces of the function. The program whose scope is later is usually at the beginning of the file until the macro definition scope is terminated using the # UNDEF command.

(3) do not use Macros in strings. If the macro name appears in strings, it will be processed according to strings.

The following describes how to use the code.

#include <stdio.h>#define N 9int main (){int i,a[N];for(i=0;i<N;i++){a[i]=i;printf("%d\t",a[i]);if((i+1)%3==0)printf("\n");}//#undef Nprintf("%d\n",N);}

The running result is:

0       1       23       4       56       7       89Press any key to continue

Here we will mainly introduce the macro scope. When # undef n is commented out in the above Code, the following print statement can be printed normally; however, when # undef n is not commented out, the error c2065: 'n': Undeclared identifier error occurs, indicating that N is not defined. Next let's take a look at the use of macros with parameters.

2. With Parameters

# Define macro name (parameter table) String

Note:

(1) There cannot be spaces between macro names and parameter brackets

(2) macro replacement is only for replacement, without calculation or expression solving. Pay special attention to this.

(3) function calls are performed when the program is running after compilation and memory is allocated. Macro replacement is performed before compilation without memory allocation

(4) The macro dummy combination (the so-called dummy combination is similar to the process in which the real parameter replaces the form parameter in the function call process) does not have a type, and there is no type conversion.

(5) macro expansion to extend the source program, function call will not

Next, let's take a look at the next typical Linux application:

# Define min (x, y) ({typeof (x) _ x = (x); typeof (y) _ y = (y); (void) (& _ x = & _ y); _ x <_ y? _ X: _ y ;})

# Define max (x, y) ({typeof (x) _ x = (x); typeof (y) _ y = (y); (void) (& _ x = & _ y); _ x> _ y? _ X: _ y ;})

In the two macros above, we found such a code (void) (& _ x = & _ y). Many readers may feel a little nervous. What does this mean ?! As a matter of fact, we will know through a detailed analysis. First, let's take a look at "=". This is a logical expression that requires the comparison types on both sides to be consistent. If our & X and & Y types are inconsistent, for example, if one is char * and the other is int *, it is not of the same type. When GCC is used for compilation, a warning message is displayed. If vc6 is used, an error c2446 is returned: '=': no conversion from 'Char
* 'To 'int *'. This code (void) (& _ x = & _ y); the function here is equivalent to executing a simple judgment operation, we are used to determine whether the types of X and Y are consistent. Don't underestimate this code. If you learn how to use it, it will bring a lot of convenience to your code. The following is a small example:

#include<stdio.h>   void print(){printf("hello world!!!\n");return ;}void main(int argc,char*argv)  { print();return ;}  

The running result is:

hello world!!!Press any key to continue

Now let's modify the code and see the running result:

#include<stdio.h>   void print(){printf("hello world!!!\n");return ;}void main(int argc,char*argv)  { #define print() ((void)(3))print();return ;}  

The running result is:

Press any key to continue

The result here does not contain our previous Hello world !!!, We can see that the function is not called at this time, because we use # define print () (void) (3), so that the function print () is called later () the function is converted to an empty operation, so this function will not be called in the subsequent code, just as it is "washed away. Do you think of our previous article "the little secret assertions of C language"? We can also use this method to close assertions. The method is similar, I will not explain it here. Interested readers can try it on their own. It seems that the end of this article should be over, but the readers will have another question? In # define
Min (x, y) ({typeof (x) _ x = (x); typeof (y) _ y = (y); (void) (& _ x = & _ y); _ x <_ y? In _ x: _ y;}), why do we need to use conversions like typeof (y) _ y = (y? Instead of directly using typeof (x) = typeof (y) or (void) (& X = & Y); x <Y? What about X: Y? If we use typeof (x) = typeof (Y), it is like using char = int, which is not allowed. We use a typeof (y)
The conversion of _ y = (Y) is to prevent X and Y from being an expression, such as X = I ++, if the conversion is not performed, I ++ executes the operation several more times and does not obtain the expected result. However, if typeof (y) _ y = (Y) is used) this conversion will not cause such a problem. Next, let's take a look at how to use macro definition to implement variable parameters. First, let's look at the implementation method.

# Define print (...) printf (_ va_args __)

Look at the macro above, where "..." refers to variable parameters. The implementation of variable parameters is to replace _ va_args __with the content represented by "...". You can see the following code.

#include<stdio.h>   #define print(...)   printf(__VA_ARGS__)  int main(int argc,char*argv)  {  print("hello world----%d\n",1111);    return 0;  }

The running result is:

root@ubuntu:/home/shiyan# ./arghello world----1111

Next, let's look at it.

# Define printf (TEM,...) fprintf (stdout, TEM, ##_ va_args __)

If you are not familiar with fprintf, you can check the function manual.

#include<stdio.h>   #define print(temp, ...) fprintf(stdout, temp, ##__VA_ARGS__) int main(int argc,char*argv)  {  print("hello world----%d\n",1111);    return 0;  }

The running result is:

root@ubuntu:/home/shiyan# ./arghello world----1111

Temp is used to set the output string format, and "..." is a variable parameter. Now the question is, why do we use "#" in macro definition? What if we don't use? Take a look at the following code:

#include<stdio.h>   #define print(temp, ...) fprintf(stdout, temp, __VA_ARGS__) int main(int argc,char*argv)  {  print("hello world\n");    return 0;  }

The following error occurs during compilation:

root@ubuntu:/home/shiyan# gcc arg.c -o argarg.c: In function ‘main’:arg.c:7:2: error: expected expression before ‘)’ token

Why is the above error? Now let's analyze it. Let's Replace the Macro. Print ("Hello world \ n") is changed to fprintf (stdout, "Hello world \ n",) so we can find a comma behind it, which leads to an error. If there is "#", this will not happen, this is because if a variable parameter is ignored or empty, the "#" operation will remove the comma before the Preprocessor. If a variable parameter exists, it can also work normally. After talking about "#", we also need to talk about "#". Let's take a look at the following code:

#include<stdio.h>   #define return_exam(p) if(!(p)) \{printf("error: "#p" file_name:%s\tfunction_name:%s\tline:%d .\n",\__FILE__, __func__, __LINE__); return 0;}int print(){return_exam(0);}int main(int argc,char*argv)  {  print();printf("hello world!!!\n");    return 0;  }

The running result is:

root@ubuntu:/home/shiyan# ./argerror: 0 file_name:arg.cfunction_name:printline:9 .hello world!!!

The error file name, function name, and row number are printed in the running result. The macro definition is used to check whether the return value of the function is correct. It is only used to reflect the macro we want to explain. Therefore, the code is simplified to the maximum extent, readers should learn this method when writing their own code. "#" Is used to concatenate the macro parameters following it, that is, add a double quotation mark (double quotation mark) to each macro variable after the macro variable is replaced, this makes "# P" taste "" p ". We find that the" on both sides disappears. Next let's take a look at the condition compilation of the last knowledge point.

Iii. Conditional compilation

Conditional compilation commands # If, # else, # Elif, # endif, # ifdef, # ifndef. The meaning of Conditional compilation commands is very simple, similar to the IF statement we learned.

General Format

# If constant expression

Segment 1;

[# Else
Procedure 2;]

# Endif

Function: when the expression is not 0 ("logical truth"), compile the program segment 1; otherwise, compile the program segment 2.

General Format

# Ifdef identifier

Segment 1;

[# Else
Procedure 2;]

# Endif

Function: if the "identifier" has been defined by the # define command, compile the program segment 1; otherwise, compile the program segment 2.

# Ifndef identifier
Segment 1;

[# Else
Procedure 2;]

# Endif
Function: if the "identifier" is not defined by the # define command, compile the program segment 1; otherwise, compile the program segment 2.

After learning the Conditional compilation command, we should not delete the code as we wish when debugging the code, if we don't want a piece of code to be compiled, we can use the Conditional compilation command to comment it out. For example:

# If (0)

Annotation code segment;

# Endif

You can also enable the code when necessary, instead of having to re-edit the code and find it deleted.

Note that constant expressions are evaluated during compilation. Therefore, expressions can only be constants or defined identifiers, but not variables, you cannot think of operators that evaluate values during compilation, such as sizeof.

The following code is used:

# Include <stdio. h> # define n 1int main (INT argc, char * argv) {int A = 3; # if () printf ("# The expression after if is variable \ n"); # endif # If (n) printf ("# The expression after if is defined, not 0 --- success \ n "); # elseprintf (" # The expression after if is defined, and not 0 --- fail \ n "); # endif return 0 ;}

The running result is:

# The expression after if is defined and not 0 --- successpress any key to continue

When we look at the code above, our expression is variable A and it is not printed out, so we cannot use the variable in the subsequent expression. What if we use the sizeof operator? Let's take a closer look at the results of the following code.

# Include <stdio. h> int main (INT argc, char * argv) {int A = 9; # If (sizeof ()) printf ("# The expression after if contains the sizeof operator \ n"); # endif return 0 ;}

The following error occurs during compilation:

fatal error C1017: invalid integer constant expression

Therefore, we must keep these two points in mind when using Conditional compilation. Constant expressions cannot be variables or operators that contain sizeof and other values during compilation.

Next let's take a look at the last # pragma command.

The general format is:

# Pragma Parameters

Below are several frequently used forms

1. # pragma message ("message ")

Take a look at the following code.

# Include <stdio. h> # define fdsaint main (INT argc, char * argv) {# ifdef fdsa # pragma message ("fdsa defined") # endifreturn 0 ;}

During compilation, we can see the output "fdsa has been defined" in the compilation output window. In this way, we can output a lot of information we need in some places we want.

2. # pragma once

If we add this command at the beginning of the header file, we can ensure that our header file is compiled only once.

3. # pragma hdrstop

This command indicates that the header file has been compiled so far, and you do not need to compile it later.

4. # pragma pack ()

Set the byte alignment length. This instruction has been explained in "alignment of the byte secrets in C Language" and will not be repeated here.

5. # pragma warning (Disable: m n; once: H; error: K)

The M and N warning messages are not displayed. The H warning messages are only reported once, and the K warning messages are treated as an error.

Now the pre-processing is over. Due to my limited level, improper or incorrect content in my blog is inevitable, and I hope readers will criticize and correct me. Readers are also welcome to discuss relevant content. If you are willing to share your comments, please leave your valuable comments.

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.