C language-macro definition

1. Pretreatment

  The first step of compiling a C language program is the preprocessing stage, this stage is the stage where the macro comes into play. The C preprocessor performs some textual operations on the source code before it is compiled. The main tasks include deleting comments, inserting the file content that is #included, defining and replacing symbols defined by #define, and determining whether part of the code is based on conditions Compile (#if) to compile. The operation of "textual nature" refers to replacing one paragraph of text with another paragraph, regardless of any semantic content. Macro is just a text replacement tool in the C preprocessing stage, and it is invisible to the binary code after compilation

2. Macro definition usage

① Macro constant

  The most commonly used usage of #define is to use #define to define a symbolic constant. When you want to modify it, you only need to modify the #define statement, and you don't need to modify every code.
Example:

#include"stdio.h"
#define PI 3.14
#define STR "圆周率约等于"
int main()
{
    
    
	printf("%s %f",STR,PI); //预处理时会被替换为 printf("%s %f","圆周率约等于",3.14);
	return 0;
}

 
  
  

operation result:
Insert picture description here


②Macro statement

  We can also define one or more statements with macros.
Example:

#include"stdio.h"
#define Print printf("hello world!")
int main()
{
     
     
	Print;  //预处理时会被替换为 printf("hello world!");
	return 0;
}

  
   
   

Operation result:
Insert picture description here

③Macro function

  I can also use macros to define functions, because macro definitions can also take parameters.
Example:

#include"stdio.h"
#define Print(str) printf("%s",str)
int main()
{
     
     
	Print("这是一个只有一条语句的宏函数!");
    //预处理时会被替换为 printf("%s","这是一个只有一条语句的宏函数!")
	return 0;
}

  
   
   

Insert picture description here

④Other

1. #undef is used to undo the macro definition, the usage is as follows:

#define PI 3.141592654

// code
# undef PI
//PI is invalid from the beginning

2. Use ifndef to prevent header files from being repeatedly included and compiled

  This is a type of macro definition, which can be used for branch selection according to whether a variable has been defined, generally used for debugging, etc. In fact, it should be exactly the three preprocessing functions (macro definition, file inclusion and Conditional compilation)—conditional compilation. When the C language compiles the program, it will first "preprocess" according to the preprocessing command. The C language compilation system includes preprocessing, compilation and linking.

#ifndef x //先测试x是否被宏定义过
#define x //如果没有宏定义下面就宏定义x并编译下面的语句
...
...
...
#endif //如果已经定义了则编译#endif后面的语句

 
  
  

The condition indicator #ifndef checks whether the precompiled constant has been defined by the macro before. If it is not defined by a macro before, the value of the condition indicator is true, so all statements from #ifndef to #endif are included for compilation processing. Conversely, if the value of the #ifndef indicator is false, the line between it and the #endif indicator will be ignored. The main purpose of the conditional indicator #ifndef is to prevent repeated inclusion and compilation of header files.
  Don't ignore the #ifndef in the header, this is a very critical thing. For example, you have two C files, both of which include the same header file. When compiling, these two C files have to be compiled together into a runnable file, so the problem comes, a lot of declaration conflicts.

So put the contents of the header file in #ifndef and #endif. Regardless of whether your header file is referenced by multiple files, you have to add this. The general format is this:

  #ifndef <标识>

# define <identification>

......

#endif

<Identification> can be freely named in theory, but the "identification" of each header file should be unique. The naming rule of the logo is generally that the header file name is all uppercase, followed by underscores, and the "." in the file name is also underlined, such as: stdio.h


  #ifndef _STDIO_H_

#define STDIO_H

......

<span class="token macro property">#<span class="token directive keyword">endif</span></span>

#ifndef xxx //If xxx is not defined
#define xxx //define xxx
#endif //End If
this usage is mainly in the header file, it is mainly to prevent repeated include of the class, so add the front before the header file of the class Two, replace xxx with the class name, and add the last sentence at the end


3. Macro definition related function

①Line break "\"

  When we define a macro statement or a macro function, it is impossible to always have one statement. What if there are many statements? Are all written on one line? Obviously the code is not beautiful and the readability is not good, so there are multiple statements When, we add "\" at the end of each line (except for the last line), which represents the meaning
of line break. Example:

#include"stdio.h"
#define Print   printf("这是第1条语句\n");\
 		    	printf("这是第2条语句\n");\
 		    	printf("这是第3条语句\n")

# define Show(str1,str2,str3)
{ printf("%s\n",str1); printf("%s\n",str2); printf("%s\n",str3);\



}
int main ( )
{
Print ; // Macro function with no parameters
Show ( "first" , "second" , "third" ) ; // Macro function with parameters
return 0 ;
}

Operation result:
Insert picture description here

②String character "#"

  "#" means "stringification". The # that will appear in the macro definition converts the following parameter into a string.
Example:

#include"stdio.h"
#define Print(str)\
{\
	printf(#str"的值是%d",str);\	
}
int main()
{
    
    
	int x=3,y=4;
	Print(x+y); //此处等价于printf("x+y""的值是%d",x+y);
	            //#str等价于"x+y",所以#str不需要再用双引号引起来 
	return 0;
}

 
  
  

Operation result:
Insert picture description here


③ Fragment connector "##"

  "##" is a way of separating and connecting. Its function is to separate first and then force the connection. In ordinary macro definitions, the preprocessor generally interprets spaces as segment marks, and compares each segment with the previous one, and replaces the same ones. But the result of this is that there are some spaces between the replaced segments. If we do not want these spaces, we can add some ## to replace the spaces.
example:

#include"stdio.h"
#define Add(n,value)\
{\
	num##n+=value;\
 } 
int main()
{
    
    
	int num1=1;
	int num2=10;
	Add(2,10); //等价于num2+=10; 这里把num和2连接成了num2 
	printf(" num1=%d\n num2=%d",num1,num2); 
	return 0;
}

 
  
  

4. Clever use of macro function

①Type transfer

  We know that although functions can pass parameters, they cannot pass types as parameters. Sometimes we need to use STL templates in order to achieve the reusability of functions, but we have another option at this time, which is to write macro functions.
Example:
A function to open up memory

#define Malloc(type,size) (type*)malloc(sizeof(type)*size)

 
  
  

At this time, we can only open up various types of memory by passing the type and capacity as parameters.

int *p=Malloc(int,100); //开辟int类型的内存
char *q=Malloc(char,100); //开辟字符类型的内存

 
  
  

② Pass the array

  When an array is passed as a function parameter, it will lose its array characteristics, that is, the sizeof() function cannot be used to calculate the size of the array. For example, when we write a sorting function, we not only need to know the first address of the array when sorting, but also need to know the array. The size of the array, but when the array name is passed as a parameter, the array size cannot be known. At this time, our function needs to pass the second parameter, which is the size of the array, so the function should be written as Sort(int *a, int size). But the macro function can solve this problem.
Example:
The following uses a macro function to write an insertion sort algorithm

#include"stdio.h"
#define InsertSort(list)\
{\
	int s=sizeof(list)/4;\
	int i,j;\
	for(i=2;i<=s;i++)\
	{\
		list[0]=list[i];\
		for(j=i-1;list[j]>list[0];j--)\
				list[j+1]=list[j];\	
		list[j+1]=list[0];\		
	}\ 
}
int main()
{
    
    
	int num[]={
    
    0,2,5,7,3,1,8,0,8,22,57,56,74,18,99,34,31,55,41,12,9,4};
	InsertSort(num);
	for(int i=1;i<sizeof(num)/4;i++)	
		printf("%d ",num[i]);
	return 0;
} 

 
  
  

Operation result:
Insert picture description here
Of course there are many clever usages of macro definitions, not all of them are listed here

Five. Matters needing attention

① The problem of operator precedence

#define MULTIPLY(x, y) x * y

 
  
  
  • 1

  This is a very simple multiplication function. When calculating MULTIPLY(10, 10), the result is 100, everyone knows this, but when you calculate MULTIPLY(5+5, 10), do you think the result is still 100? Of course not ,MULTIPLY(5+5, 10)=5+5*10=55, so the result is 55, so we should pay special attention to the priority of operators when writing macro functions. A safer way of writing here should be written like this

#define MULTIPLY(x, y) ((x)*(y))

 
  
  

②Repeated call of macro parameters

#define MAX(a,b) ((a)>(b)?(a):(b))
int a=0;
int b =1;
int c =MAX(++a,++b);

 
  
  

Many people here think that c=MAX(1,2)=2; in fact, the above code is equivalent to

int c =((++a)>(++b)?(++a):(++b));

 
  
  

It can be seen that in fact, ab is added twice, so c=1>2? 2:3=3, so the result is 3.

③The problem of semicolon swallowing

#include"stdio.h"
#define FUN(n)\
{\
	while(n>0)\
	{\
		if(n==3)\
			break;\	
	}\	
}
int main()
{
    
    
	int num=10;
	if(num>0)
		FUN(num);
	else
		num=-num;
	return 0;
}

 
  
  

  There seems to be no problem with the code, but an error is reported as soon as it is compiled. The compiler displays "error:'else' without a previous'if'". It turns out that the FUN function is a code block, and then if(num>0) FUN(num) ; It is equivalent to if(num>0) {…}; Isn’t this just putting a semicolon after the braces? So of course the else lacks if. At
  this time, we can use do{…}while(0) to solve this Question, it's okay to write as follows, because a semicolon is needed after while()

#define FUN(n)\ 
do\
{
    
    \
	while(n>0)\
	{
    
    \
		if(n==3)\
			break;\	
	}\	
}while(0)

 
  
  

④Recursive call problem

#define NUM (4 + NUM)

 
  
  

  According to the previous understanding, (4 + NUM) will expand to (4 + (4 + NUM)), and then expand until the memory is exhausted. However, the strategy adopted by the preprocessor is to expand only once. In other words, NUM will only expand to (4 + NUM), and the meaning of NUM after expansion will be determined according to the context.

⑤ Macro parameter preprocessing

  If the macro parameter contains another macro, then the macro parameter will be fully expanded before being substituted into the macro body, unless the macro body contains # or ##.

There are the following macro definitions:

#define A(y) X_##y
#define B(y) A(y)
#define SIZE 1024
#define S SIZE

 
  
  

A(S) will be expanded into X_S. Because the macro body contains ##, the macro parameters are directly substituted into the macro body.
B(S) will be expanded into X_1024. Because the macro body of B(S) is A(S), there is no # or ##, so S will be fully expanded to 1024 before being substituted, and then substituted into the macro body, becoming X_1024.

Guess you like

Origin blog.csdn.net/qq_44378854/article/details/109298352