C/C++ macro definitions and macro functions

1 Overview

C/C++ macro definitions and macro functions are very useful, because recently when I look at Android’s jni code, I always see the macro definition as shown in the figure below: After
Insert image description heredefining it, just use it directly as follows:

JMI_DECLARE_CLASS(Context,android.content);

In this way, some logically repeated codes can be managed very concisely, so that when making modifications, only the macro definition part needs to be modified. The above method is how to use macro functions. Macro definition is actually a statement defined using #define in C/C++, as shown below:

#define PI 3.14 // 宏替换
#define MAX(a,b) ((a)>(b)?(a):(b))// 宏函数

As shown above, macro definitions are divided into macro substitutions and macro functions. This article will introduce the differences between these two types and how to use them.

2. Macro replacement

We all know that in C language, #everything starting with the number is a preprocessing instruction. Our macro replacement is defined using #define values ​​or calculations. It should be noted that macro replacement is a simple replacement, a direct replacement. We can introduce macro replacement through an example:

Suppose we need to define a CONST constant. The value of this constant is: 1+2. The code is as follows:

#include<iostream>
#define CONST 1+2

using namespace std;

int main() {
    
    
	int res = 3 * CONST;
	cout << "the result is: " << res << endl;
}

Many readers may think that the result here is 9, but the running result is 5:
Insert image description here
Why does this happen? This is what we call macro replacement. Macro replacement is just a simple replacement and does not have the function of calculation. What follows CONST here 1+2will be directly replaced into our expression:. int res = 3*CONST;The replacement should look like: int res = 3*1+2;According to the priority of arithmetic operations, the result is 5. If we want the result to be 9 as we want, It is necessary to add parentheses to the expression after the macro definition to maintain priority. For example, #define CONST (1+2)if we want to use macro substitution correctly, we must pay attention to understanding the nature of macro substitution. It's just a simple replacement.
注意:宏替换后的语法需要满足C/C++的语法,替换之后的语句,不能违背C/C++的语法,否则会编译不通过。其次宏不是语句,所以末尾没有分号

3. Macro function

3.1 Basic use

Macro function is also a type of macro replacement, and the focus is also replacement. The only difference is that the expression behind the macro function needs to be calculated. As shown below:

#include<iostream>
#define MAX(a,b) ((a)>(b)?(a):(b))

using namespace std;

int main() {
    
    
	int res = MAX(1,3);
	cout << "the result is: " << res << endl;
}

Running results:
Insert image description here
In the above code, we use a macro function to define a macro function for finding the maximum value. Earlier we saw that when doing replacement, the macro we defined will be replaced into the code. At this time, the priority will be will change, so try to add parentheses around each parameter when we define a macro function. In addition, macro functions can ignore types: MAX(1,3),MAX(1.1,1.3),MAX('A','B')they are all legal.

3.2 Multi-line writing method of macro replacement

The macro functions we introduced earlier are all defined in a single line. So how should we write our macro function if it has multiple lines? There is a little difference between the writing method and the actual writing of the function. When breaking the line, you need to add a backslash "\"to separate it, as shown below:

#include<iostream>
#define SWAP(a,b)do{
      
      \
int temp = (a);\
(a) = (b);\
(b) = temp;\
}while(0);

using namespace std;
int main() {
    
    
	int a = 1;
	int b = 3;
	cout << "before swap: a=" << a <<" b="<< b << endl;
	SWAP(a,b);
	cout << "after swap: a=" << a << " b=" << b << endl;
}

operation result:
Insert image description here

In the above code, when we define a macro function that has multiple lines, we need to use backslashes to separate them. In the code, we can also see that when I do{}while(0)的这种写法,也可以使用if(1){}代替looked at the code in the open source library, I was curious about why it was written like this. Later I found out that it is like this The reason for writing it is to prevent conflicts with other codes when doing macro replacement.

4. Conditional compilation for macro replacement

Conditional compilation is mainly used to compile our code according to the conditions we have set in advance. In actual application scenarios, it is mainly for compatibility processing. Let’s look at a piece of code first:

#include<iostream>
using namespace std;
int main() {
    
    
#if 1
	cout << "条件编译" << endl;
#else
	cout << "不成立,不编译" << endl;
#endif
}

We can use the condition after if to allow the compiler to determine whether the condition is true during compilation, so that the corresponding code block can be entered to execute the code. Conditional compilation is completed before the program is run.充当条件编译的变量必须是全局变量或者宏,因为局部变量在编译时是没有分配内存的

In addition, if you need to judge whether the macro definition xxx exists, you can use: #ifndef xxxTo judge whether it exists, use: #ifdef xxxThis writing method can prevent conflicts caused by repeated definition of macros. If we want to cancel the definition of the macro, we can use: #undef xxx, so that we can cancel the definition of the macro xxx. After canceling, xxx will naturally become unusable.

5. Special commands and special macros

When reading large-scale project code written by others, we may see two symbols in the macro function definition "#" 和“##”. Both symbols have special functions. #The symbols can convert the input content into a string, as shown below:

#include<iostream>
#define toString(x) #x
using namespace std;

enum Person {
    
    
	MAN,
	WOMAN
};
int main() {
    
    
	cout << "男人: " << toString(MAN) << " 女人:" << toString(WOMAN) << endl;
}

In the above code, we convert the enumeration type data into string data and output it. Readers can run it to see the effect
技巧: 我们可以使用这种方式将其他类型的数据转换成字符串数据

The next thing is ##, this command is a connector, look at the example below:
Insert image description here
The above is the actual application I saw in the project, which is splicing to generate a name with identification function, which is very convenient to use:
Insert image description here
Then we may also see some Special macros, such as the following example:

#include<iostream>
using namespace std;

int main() {
    
    
	cout << "日期: " << __DATE__ <<endl<< "时间: "
		<< __TIME__<<endl << "当前行号:" << __LINE__ << endl;
}

Insert image description here

Guess you like

Origin blog.csdn.net/zxj2589/article/details/134022192