Discuss the difference between inline function and macro definition

  • 2020-04-02 00:51:34
  • OfStack

Replace macros with inline:
1. Inline functions can be debugged at runtime, but macro definitions cannot;
2. The compiler will perform security checks or automatic type conversions on the parameter types of inline functions (like normal functions), while macro definitions will not;
3. Inline functions can access the member variables of the class, but macro definitions cannot.
4. Declare the member function defined in the class at the same time, automatically convert to inline function.
Article 1
Inline functions and macro definitions
In C, the preprocessing statement #define is often used instead of a function definition. Such as:
Define MAX(a, b) ((a) > (b)? (a) : (b))
This statement causes every place in the program where the MAX(a,b) function is called to be followed by the expression ((a) in the macro definition. > (b)? (a) (b)).
Macro definition statements are overwritten with no Spaces between MAX and parentheses, and all arguments are required
Put it in parentheses. Still, it has problems:
Int a=1, b=0;
MAX (+ b); //a has been added twice
MAX (+, b + 10); //a has been added 1 time
MAX (a, "Hello"); // incorrectly comparing int and string, no parameter type checking
The evaluation of the MAX() function has different side effects depending on the size of the two parameter values.
MAX(a++,b) is 2, while a is 3.
The value of MAX(a++,b+10) is 10, and the value of a is 2.
If it were a normal function, MAX(a,"HellO") would be checked by the function call, but would not be shut out of compilation here because of the different parameter types. Fortunately, with an inline function, you can get the substitution efficiency of all macros and all the predictable states as well as the type checking of regular functions:
Inline int MAX(int a, int b)
{
Return a > B? A: b;
}
1. Difference between inline functions and macros:
          Traditional macro definition functions can cause some trouble.
          Ex:
                    # define F (x) + x x
                    Void main () {int I = 1; F (i++); }
                      Here x is going to be added twice.
              Inline functions are automatically added to the code by the compiler with the function's situation, which does not occur.
              The use of inline functions improves efficiency (eliminating a lot of assembly code for function calls such as call and ret).
2. Use of inline functions:
                All functions defined in the declaration of the class are automatically considered inline.
              Class A ()
            {
                        Void (c); // inline function;
                      Void d(){print("d() is a inline function."); }
              }
              If you want to define a global function as inline, the inline keyword is available.
              Inline a(){print("a() is a inline function."); }
Note:
          Complex operations in inlined functions will not be inlined. Such as: loop and recursive call.
Conclusion:
          It is efficient to define short and simple functions as inline.

Article 2
8.5.1 replace macro code with inline
The C++ language supports function inlining in order to improve the efficiency (speed) of function execution.
In C programs, you can use macro code to increase execution efficiency. The macro code itself is not a function, but it works like one. The preprocessor copies macro code instead of function CALL, eliminating the process of parameter pressing, generating assembly language CALL CALL, returning parameter, executing return, etc., thus improving the speed. The biggest drawback to using macro code is that it is error-prone, and the preprocessor often has unexpected marginal effects when copying macro code. For example,
# define MAX (a, b)             (a) > (b)? (a) : (b)
statements  
Result = MAX(I, j) + 2;
Will be interpreted by the preprocessor as
Result = (I) > (j)? (I) : (j) + 2;
Because the operator '+' has a higher priority than the operator' :', the above statement is not equivalent to the expected
Result = ((I) > (j)? (I) : (j)) + 2;
If I rewrite the macro code as
# define MAX (a, b)             (a) > (b)? (a) : (b))
Errors caused by priorities can be resolved. But even using modified macro code, such as statements, is not foolproof
Result = MAX (i++, j);
Will be interpreted by the preprocessor as
Result = (i++) > (j)? (i++) : (j);
There is another drawback to using macro code for C++ : the inability to manipulate private data members of a class.
Let's see how C++ 's "function inline" works. For any inline function, the compiler places the declaration of the function (including name, parameter type, return value type) in the symbol table. If the compiler does not find an error in the inline function, the code for that function is also placed in the symbol table. When an inline function is called, the compiler first checks that the call is correct (for type safety checking, or for automatic type conversion, as with all functions). If correct, the inline function code replaces the function call directly, eliminating the overhead of the function call. This process is significantly different from preprocessing because the preprocessor cannot perform type safety checks or perform automatic type conversions. If the inline function is a member function, the address of the object (this) will be placed in the appropriate place, which the preprocessor cannot do.
The C++ language's function inline mechanism combines the efficiency of macro code with added security and the freedom to manipulate class data members. So in C++ programs, you should replace all macro code with inline functions, and "assert" is probably the only exception. Assert is a macro that only works in the Debug version and is used to check for "shouldn't" situations. In order not to cause a difference between the Debug and Release versions of your program, assert should not cause any side effects. If assert is a function, the Debug version will differ from the Release version due to changes in memory and code caused by function calls. So assert is not a function, it's a macro. (see section 6.5, "using assertions")
8.5.2 programming style of inline functions
The keyword inline must be placed with the body of the function definition to make the function inline. Simply placing inline before the function declaration does not work. The following style of function Foo cannot be inline:
Inline void Foo(int x, int y);   // inline is only placed with the function declaration
Void Foo(int x, int y)
{
...
}
The following style of function Foo becomes inline:
Void Foo(int x, int y);  
Inline void Foo(int x, int y) // inline with the function definition body
{
...
}
So inline is a "keyword for implementation", not a "keyword for declaration". In general, the user can read the declaration of the function, but cannot see the definition of the function. Although the inline keyword appears before the declaration and definition body of inline functions in most textbooks, I don't think inline should appear in the declaration of functions. This detail, while not affecting the functionality of the function, embodies a fundamental principle of the high quality C++/C programming style: declarations and definitions are not to be confused, and users do not need or should not know whether functions need to be inline.
A member function defined in a class declaration automatically becomes an inline function, for example
Class A,
{
Public:
Void Foo(int x, int y) {... }   // automatically becomes an inline function
}
Putting the body of the definition of a member function in a class declaration, while convenient for writing, is not a good programming style.
/ / header files
Class A,
{
Public:
Void Foo(int x, int y);  
}
// definition file
Inline void A::Foo(int x, int y)
{
...
}
8.5.3 use inlining with caution
Inlining makes functions more efficient, so why not define all functions as inline?
If all functions are inline, do you still need the keyword "inline"?
Inlining is at the expense of code bloat (replication), and only saves the overhead of function calls, thus increasing the efficiency of function execution. If the time it takes to execute the code inside the function is more expensive than the function call, the efficiency gains are minimal. On the other hand, copying code at every call to an inline function increases the total amount of code in the program and consumes more memory. Inlining should not be used in the following situations:
(1) if the code in the function body is relatively long, using inlining will lead to high memory consumption.
(2) if there is a loop in the function body, the time to execute the code in the function body is more expensive than the function call.
Class constructors and destructors can be misinterpreted as being more efficient with inlining. Beware that constructors and destructors may hide behavior such as "stealthy" execution of constructors and destructors for base classes or member objects. So don't just throw the body of a constructor or destructor into a class declaration.
A good compiler will automatically uninline undeserving functions based on the body of the function definition (which further illustrates that inline should not appear in the declaration of the function).
8.6 some observations
The mechanisms of overloading, inline, default parameters, and implicit conversion in C++ show many advantages, but there are hidden dangers behind them. Just like people's diet, eating less and eating too much is not advisable and should be just right. We should treat the new C++ mechanisms dialectically and use them appropriately. This is the art of programming, though it makes us a little more thoughtful and a little less fun.
Chapter 9: constructor, destructor and assignment function of class
Constructors, destructors, and assignment functions are the most basic functions of each class. They are so common that it is easy to be careless. In fact, these seemingly simple functions are as dangerous as a sewer without a lid.
Each class has only one destructor and one assignment function, but you can have multiple constructors (including a copy constructor and others called normal constructors). For any class A, if you don't want to write the above functions, the C++ compiler automatically produces four default functions for A, such as
A (void); // default no-argument constructor
A (const A & A); // default copy constructor
~ A (void); // default destructor
A & operate =(const A & A); // default assignment function
This makes one wonder why programmers write functions when they can generate them automatically.
Here's why:
(1) if the "default no-argument constructor" and "default destructor" are used, the chances of autonomous "initialization" and "cleanup" are given up, and the kindness of C++ inventor Stroustrup is in vain.
(2) "default copy constructor" and "default assignment function" are implemented by "bit copy" instead of "value copy". If the class contains pointer variables, these two functions are bound to fail.
For the C++ programmer who hasn't suffered enough, if he says it's easy to write constructors, destructors, and assignment functions, he can be a no-brainer, showing that his understanding is superficial and needs to be improved.
This chapter takes the design and implementation of class String as an example to explain the truth that is ignored by many textbooks. The structure of String is as follows:
The class String
{
  Public:
String(const char * STR = NULL); // ordinary constructor
String (const String & other); // copy constructor
~ the String (void); // destructor
String & copy =(const String &other); // assignment function
  Private:
char     * m_data; // is used to save strings
};
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
At program compilation time, the compiler replaces the call expression of the inline function that appears in the program with the function body of the inline function. Obviously, this approach does not produce turned back problems, but because of the function at compile time to take the code is alternative to the program, so can increase the amount of target code, which further increases the space overhead, and in the time when you don't like a function call on a commission basis, visible it is increased at the expense of object code for economy of time.

Related articles: