The difference between a functional macro definition and a normal function

  • 2020-04-02 01:41:28
  • OfStack

In C and C++ languages, an identifier is allowed to represent a string, called a macro, which can be a constant, an expression, a format string, and so on. When compiling preprocessing, all "macro names" that appear in the program are substituted with strings in the macro definition. This is called "macro substitution" or "macro expansion". The macro definition is done by the macro definition command in the source program. Macro substitution is done automatically by the preprocessor. If a string is an expression, we call it a functional macro definition. What's the difference between a functional macro definition and a normal function?

Let's take the following two lines of code as an example to expand the description:
Function macro definition: #define MAX(a,b) ((a) > (b)? (a) : (b))
Normal function: MAX(a,b) {return a > B? A: b; }

(1) the parameters defined by functional macros have no type, and the preprocessor is only responsible for formal substitution without parameter type checking, so be careful when passing parameters.

(2) the code that calls the real function is different from the instructions generated by code compilation that calls the functional macro definition.

If MAX is a normal function, its body returns a > B? A: b; To compile the build instruction, each call that occurs in the code also compiles and generates the pass-through instruction and the call instruction. If MAX is a functional macro definition, the macro definition itself does not have to compile the generated instruction, but every time the code calls the compiled instruction is equivalent to a function body, instead of just a few call and call instructions. Therefore, the object file generated by compiling the functional macro definition is larger.

(3) function macro definition to pay attention to the format, especially the parentheses.

If the above function macro definition is #define MAX(a, b) (a) > B? A :b), leave out the inner bracket, and the macro expands to k = (I &0x0f) > J & 0 x0f? I &0x0f:j&0x0f), the priority of the operation is wrong. By the same token, the outer bracket of the macro definition cannot be omitted. If the macro in the function is replaced by ++MAX(a,b), then the macro expansion becomes ++(a). > (b)? (a) (b), the operational priority is also wrong.

(4) if the function parameter is an expression, then the call of the ordinary function is different from the replacement process of the function macro definition.

When a normal function is called, the value of an argument expression is first evaluated and then passed to the parameter. If the argument expression has a SideEffect, these sideeffects occur only once. For example, MAX(++a, ++b), if MAX is a normal function, a and b only increase once. But if MAX is defined as a functional macro, it's going to be k = ((++a)). > (+ + b)? (++a):(++b)), a and b don't have to go up once or twice. So if the argument is an expression, be careful when replacing the function macro definition.

(5) functional macro definitions tend to result in lower code execution efficiency.

Take a look at the following code:


int a[]={9,3,5,2,1,0,8,7,6,4};
int max(n)
{
    return n==0?a[0]:MAX(a[n],max(n-1));
}
int main()
{
    max(9);
    return 0;
}

If the ordinary function, through recursion, the maximum desirable time complexity is O (n). But if the function macro definition, the macro expansion is (a[n]) > Max (n - 1)? A [n]: Max (n-1)), where Max (n-1) is called twice.

Although functional macro definition compared with ordinary function has many shortcomings, but as long as the careful use will significantly improve the execution efficiency of the code, eliminating the allocation and release, after all, the stack frame, preach to participate, the return value and a series of work, so those short and is frequently called functional macro definition function is often used in place of the implementation.


Related articles: