#define is a macro definition command provided in the C language. Its main purpose is to provide programmers with a certain degree of convenience in programming and to improve the operating efficiency of the program to a certain extent. However, students often cannot understand the command while learning. In essence, there is always some confusion here. This command is misused when programming, making the program run inconsistently with the intended purpose, or when reading the program written by others, the operation result is misunderstood. unfavorable.
1 #define command analysis
1.1 The concept of #define
The #define command is a macro definition command in the C language. It is used to define an identifier as a string. The identifier is called the macro name, and the defined string is called the replacement text.
This command has two formats: one is a simple macro definition, and the other is a macro definition with parameters.
(1) Simple macro definition:
#define <macro name> <string>
Example: #define PI 3.1415926
(2) Macro definition with parameters
#define <macro name> (<parameter table>) <macro body>
Example: #define A (x) x
After an identifier is defined by a macro, the identifier is a macro name. At this time, the macro name appears in the program. Before the program is compiled, the macro name is replaced with the defined string. This is called macro replacement. Compilation is performed after replacement. Macro replacement is a simple replacement.
1.2 When Macro Replacement Occurs
In order to truly understand the role of #define, let's take a look at the processing of C language source programs. When we compile the written source program in an integrated development environment such as Turbo C, we actually go through several processes of preprocessing, compilation, assembly, and linking, as shown in Figure 1.
Source program
Preprocessor
Modified source program
translater
Assembler
Assembler
Relocatable target program
Connector
Executable target program
Figure 1 C language compilation process
The preprocessor generates the output of the compiler, which implements the following functions:
(1) File contains
You can expand #include in the source program to the body of the file, that is, locate and expand the included .h file to where #include is located.
(2) Conditional compilation
The preprocessor includes or excludes a part of the source program according to the #if and #ifdef compilation commands and subsequent conditions, and usually converts the excluded statements into blank lines.
(3) Macro expansion
The preprocessor expands the references to macros appearing in the source program file into corresponding macro definitions, which is the function of #define described in this article, which is done by the preprocessor.
The source program processed by the preprocessor is all different from the previous source program. The work performed at this stage is only pure replacement and expansion, without any calculation function, so as long as you can really understand this when learning #define command, This will not cause misunderstanding and misuse of this command.
2 #define Common Problems in Use
2.1 Problems in the use of simple macro definitions
In the use of simple macro definitions, when the string represented by the replacement text is an expression, it is easy to cause misunderstanding and misuse. The following example:
Example 1 #define N 2 + 2
void main ()
{
int a = N * N;
printf ("% d", a);
}
(1) Problems: In this program, there is a macro definition command. The character string represented by macro N is 2 + 2. Macro N is used in the program. When students read this program, the problems that tend to arise are Solve N as 2 + 2 = 4, and then use multiplication when calculating a in the program, that is, N * N = 4 * 4 = 16. In fact, the result of this question is 8, why is there such a large deviation?
(2) Problem analysis: As described in Section 1, the macro expansion is completed in the preprocessing stage. At this stage, the replacement text is only regarded as a string, and no calculation will occur. In the expansion, it is in the macro N. Where it appears, it simply uses the string 2 + 2 instead of N, and does not add any symbols, so the result of the expansion of the program is a = 2 + 2 * 2 + 2, after calculation = 8, this is the macro replacement In essence, how to write a program to complete the operation with a result of 16?
(3) Solution: Write the macro definition as follows
#define N (2 + 2)
This can be replaced with (2 + 2) * (2 + 2) = 16
2.2 Problems with macro definitions with parameters
In the use of macro definitions with parameters, it is easy to cause misunderstanding. For example, we need to make a macro replacement that can square any number. This requires the use of parameters in order to replace the parameters in the macro definition with actual parameters in the program. It is easy for ordinary students to write the following form:
#define area (x) x * x
This is very easy to cause problems in use, see the following program
void main ()
{
int y = area (2 + 2);
printf ("% d", y);
}
Theoretically, the parameter given is 2 + 2, and the result should be 4 * 4 = 16, but it is wrong, because the actual result of the program is 8, it still fails to follow the rule of pure simple replacement, and it is calculated first. Again, in this program, 2 + 2 is the parameter in the area macro, which should be used to replace x in the macro definition, that is, 2 + 2 * 2 + 2 = 8. Then, if you follow the solution in (1) and enclose 2 + 2, that is, enclose x in the macro body, is it OK? #define area (x) (x) * (x), for area (2 + 2), replace with (2 + 2) * (2 + 2) = 16, which can be solved, but for area (2 + 2) / What about area (2 + 2)? Some students give the result as soon as they see this question, because the numerator and denominator are the same, and they are wrong. They still forget to follow the rule of replacing and calculating again. This question After the replacement, it will become (2 + 2) * (2 + 2) / (2 + 2) * (2 + 2), which is 4 * 4/4 * 4. According to the rule of multiplication and division, the result is 16/4 * 4 = 4 * 4 = 16, what should I do? The solution is to add a parenthesis to the entire macro body, that is, #define area (x) ((x) * (x)). Don't think this is unnecessary. Without it, it will not work.
To be able to really use the macro definition, when reading other people's programs, you must remember to replace all the use of macros in the program with the strings it represents. Do not add any other symbols on your own. Perform the corresponding calculation again, and you will not write the wrong running result. If you use your own macro replacement, when using simple macro definitions, when there is more than one symbol in the string, the parentheses are given priority. If it is a macro definition with parameters, you must give each Arguments are enclosed in parentheses, and one more parenthesis is used throughout the body of the macro. Seeing this, I can't help but ask, the definition of macros is so troublesome, so easy to make mistakes, can you abandon it? Let's take a look at the benefits of using macros in C language.
3 Advantages of Macro Definition
(1) Convenient program modification
Use simple macros to define available macros instead of a constant that is often used in programs. This way, when you change the constant, you don't need to modify the entire program. You can only modify the string defined by the macro, and when the constants are longer, we can It is more convenient to write programs with shorter meaningful identifiers. The constant change we are talking about is not changed during the running of the program, but is modified during the programming. To give a familiar example, the pi is a value commonly used in mathematics. Sometimes we use 3.14 to express it, sometimes Will use 3.1415926, etc., this depends on the accuracy required for the calculation. If we need to use it multiple times in a program, we need to determine a value that does not change in this run, but maybe later find the accuracy of the program performance There are changes, you need to change its value, which requires modifying all relevant values in the program, which will bring us some inconvenience, but if you use a macro definition and use an identifier instead, only modify the macro when modifying Just define it, and you can reduce the number of times of 3.1415926 as long as you enter it. We can define #define pi 3.1415926 in this way, which reduces the input and facilitates modification. Why not?
(2) Improve the operating efficiency of the program
The use of macros with parameters can complete the function of the function call, while reducing system overhead and improving operating efficiency. As stated in the C language, the use of functions can make the program more modular, easy to organize, and reusable. However, when a function call occurs, the scene of the calling function needs to be retained so that the sub-function can return to continue execution after execution. It is also necessary to restore the scene where the function is called after the sub-function is executed. This requires a certain amount of time. If there are more operations performed by the sub-function, this conversion time overhead can be ignored, but if the sub-function has fewer functions, even Only a little operation is completed, such as the operation of a multiplication statement, this part of the conversion overhead is relatively large, but the use of macro definitions with parameters will not cause this problem, because it is macro expansion during the preprocessing stage, No conversion is required at execution time, ie locally. The macro definition can complete simple operations, but the complex operations still need to be completed by function calls, and the target code space occupied by the macro definition is relatively large. Therefore, it is necessary to decide whether to use the macro definition according to the specific situation when using it.
4 Conclusion
This article analyzes the problems that occur when using the macro definition #define in C language, and analyzes the processing of #define from the perspective of the C source program processing process, and also explains its advantages. As long as you can understand the rules of macro expansion and master the use of macro definitions, the source program is replaced in the preprocessing stage, but the macro name appearing in the program is replaced with the corresponding string, so that you can fully enjoy on the basis of correct use Convenience and efficiency brought by the use of macro definitions
two.
Recently, I looked at com related materials. When I saw CCmdTarget implementing the com interface, I read some macro definitions in the afxdisp.h header file.
#define BEGIN_INTERFACE_PART (localClass, baseClass) \
class X ## localClass: public baseClass \
Originally this macro definition was easy to understand, but there was an extra X ## here. I have never seen this usage, I do n’t know what it means.
After asking a few friends, I didn't know.
do you know?
Maybe you do n’t know ~ Hehe, in the end, I still found relevant information, read this definition, and by the way, I knew two other definitions that are not commonly used
#define Conn (x, y) x ## y
#define ToChar (x) # @ x
#define ToString (x) #x
What does x ## y mean? Indicates that x is connected to y, for example:
int n = Conn (123,456); the result is n = 123456;
char * str = Conn ("asdf", "adf") The result is str = "asdfadf";
How is it amazing
Looking at # @ x again, it is actually a single quote for x, and the result is a const char. for example:
char a = ToChar (1); the result is a = ‘1’;
Make a cross-border test char a = ToChar (123); the result is a = ‘3’;
But if your parameter exceeds four characters, the compiler will give you an error! error C2015: too many characters in constant: P
Finally take a look at #x, I guess you also understand, he is double quotes for x
char * str = ToString (123132); becomes str = "123132";
Finally, leave a few small experiments for everyone to test:
#define Dec (x, y) (x-y)
int n = Dec (A (123,1), 1230);
n = Conn (123, Conn (123,332));
char * str = A ("12", ToString (Dec (3,1));
What will happen? Hehe hehe
three.
#define xxx () {}
Supported by Standard C
#define xxx () (())
The newly added function of GCC is mainly to prevent problems with macro expansion. By default, a; should be added when expanding, which is easy to cause problems.
CODE: #define A (a, b, c) ((a = 1; b + = 1; c = 3; a + b + c;))
#include <stdio.h>
int main ()
{
int a;
int b = 1;
int c;
int d;
d = A (a, b, c);
printf ("% d,% d,% d,% d \ n", a, b, c, d);
return 0;
}
Indicates that the macro function has a return value, and the return value of the last expression is used as the return value of the macro function.
operation result:
1,2,3,6
C language macro definition #define usage