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##b
The 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##b
with #define STR2(dev, i) dev ## #i
these 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:
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 ##