[C/C++] usage of define (advanced usage)

Although the define statement in C language looks very simple, most of the time it just adds an alias to a certain variable or function or performs simple calculations, but the function of define has other very convenient operations. It is very convenient for us to program.

1. Basic usage

#define PI    		3.1415926	            // 定义一些常量
#define LOG(...)    printf(__VA_ARGS__)     // 函数取别名
#define max(a, b)   (a) > (b) ? (a) : (b)   // 进行简单运算

LOG("你好,%s\n", "谢老板不用蟹");
printf("max(10, 8) = %d\n", max(10, 8));

output:
你好,谢老板不用蟹
max(10, 8) = 10

2. Encapsulate multiple lines of code

Add a backslash \ at the end of the line

#define PRINT               \
{
      
                                 \
    printf("define 1\n");   \
    printf("define 2\n");   \
    printf("define 3\n");   \
}

PRINT;

output:
define 1
define 2
define 3

3. Other basic type variables -> string

This function is sometimes very practical. For example, float -> char*[] If you write a function yourself, you need to perform various calculations and storage, which is very troublesome , but if you use a macro, it will become very simple.
Note: The # sign and the following ## sign can only be the parameters passed in by the macro definition.

#define String(a)  	 #a  

printf("String(92.84) = %s\n", String(92.84));

output:
String(92.84) = 92.84

4. String concatenation

4.1 The first case (macro without parameters)

The splicing between macro definitions (the ones defined must be string constants) are separated by spaces , and cannot be adjacent to each other, otherwise they will be judged as another macro.
The concatenation between the macro definition (the definition must be a string constant) and the string constant can be separated by spaces , or they can be next to each other .

#define S1          "hello"
#define S2          "world"
#define STR1        S1 S2
#define STR2        "/" S1 " the " S2 "/"	// 或者"/"S1" the "S2"/"

printf("STR1 = %s\n", STR1);
printf("STR2 = %s\n", STR2);

output:
STR1 = helloworld
STR2 = /hello the world/

4.2 The second case (macro with parameters)

If the parameters passed in by the macro definition are of string type , use ## to connect with other macro definitions whose definitions are of string type or other string constants .

If the parameter passed in by the macro definition is of other basic types , it must be connected with # to turn it into a string type .

Note: The # in front and the things immediately behind the ## can only be the parameters passed in by the macro definition.

#define S1         		" Tom "
#define S2          	" Jerry "

#define STR1(a, b)  	S1##a##S2##b     		// 拼接字符串时 a 和 b 传入的参数只能是字符串类型
#define STR2(dev, i)	dev ## #i				// 这种情况 i 就可以传入其他基本类型的变量了
#define VAR(fn, id) 	int __count_##fn##_##id	// 这种情况传入的参数不能为字符串
#define STR3(a)     	S1 S2 #a

VAR(temp, 0);
printf("STR1(\"and\", \"is friend\") = %s\n", STR1("and", "is friend"));
printf("STR2(\"dev_\", 2)", STR2("dev_", 2));
printf("STR3(\"aaa\") = %s\n", STR3("aaa"));
printf("STR3(9.9) = %s\n", STR3(9.9));

output:
int __count_temp_0;
STR1("and", "is friend") =  Tom and Jerry is friend
STR2("dev_", 2) = dev_2
STR3("aaa") =  Tom  Jerry "aaa"
STR3(9.9) =  Tom  Jerry 9.9

4.3 Precautions

#define STR1(a, b) S1##a##S2##bThe parameters a and b passed in in ① can only be of string type. For example STR1("and", "is friend"), but this definition method cannot pass in a macro that also defines a string type , such as:

#define S1         		"/"
#define S2          	"/"
#define A 				"menu"
#define B 				"osd"
#define STR1(a, b)  	S1##a##S2##b

// printf("%s", STR1(A, B));	// 错误,因为这样编译器不会将A和B定义的内容进行展开

If the parameters you want to pass in can support macros, you need to add an additional layer of intermediate conversion macros . The purpose of adding this layer of macros is to expand all the parameters of the macros in this layer, for example:

#define S1         		"/"
#define S2          	"/"
#define A 				"menu"
#define B 				"osd"
#define _STR1(a, b)  	S1##a##S2##b
#define STR1(a, b)		_STR1(a, b)

printf("%s\n", STR1(A, B));	// 正确
printf("%s\n", STR1("hello", "world"));

output:
/menu/osd
/hello/world

②If you use gcc to compile #define STR1(a, b) S1##a##S2##bwith #define STR2(dev, i) dev ## #ithese two statements , it is likely that such an error will occur:

test.c:36:37: error: pasting ""hello"" and ""world"" does not give a valid preprocessing token
  printf("C(\"hello\",\"world\")", C("hello", "world"));
                                     ^

However, this does not happen in VS, the reason is the link to the original text , that is to say, according to the C standard, the result of the ## operation must be a predefined symbol . Otherwise it is undefined. So gcc and vs express different views on this undefined behavior, the former gives an error, and the latter laughs it off . So what is a predefined symbol? It includes these: header file names, equations, preprocessed numbers, character constants, string values, punctuation marks, and single non-null characters.
So how to fix this error? If you see this error, just remove ## and there is a high probability that this error will be resolved . For example, in this example:
before removal ( wrong wording ):

#include "stdio.h"
#define S1         						"/"
#define S2          					"/"
#define STR1(a, b)  					S1##a##S2##b
#define STR2(dev, i)					dev ## #i
#define STRUCTMEMBER(Member, Value)     a.##Member = Value

struct {
    
    
    char ch;
    int i;
}a;

void main()
{
    
    
	STRUCTMEMBER(ch, 'x');
   	printf("a.ch = %c\n", a.ch);
	printf("%s\n", STR1("hello", "world"));
	printf("%s\n", STR2("hello", 0));
}

Error:
insert image description here
After removal (correct writing):

#include "stdio.h"
#define S1         						"/"
#define S2          					"/"
#define STR1(a, b)  					S1 a S2 b
#define STR2(dev, i)					dev #i
#define STRUCTMEMBER(Member, Value)     a.Member = Value

struct {
    
    
    char ch;
    int i;
}a;

void main()
{
    
    
	STRUCTMEMBER(ch, 'x');
   	printf("a.ch = %c\n", a.ch);
	printf("%s\n", STR1("hello", "world"));
	printf("%s\n", STR2("hello", 0));
}

output:
a.ch = x
/hello/world
hello0

Reference article: Pay attention to the use of macro ##

Guess you like

Origin blog.csdn.net/weixin_48896613/article/details/127686416