In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)06/03 Report--
10.1 attribute declaration: noinline & always_inline
In this section, we go on to talk about the attribute attribute declaration. Attribute can be said to be the biggest feature of GNU C. Let's move on to two properties related to inline functions: noinline and always_inline. The purpose of these two attributes is to tell the compiler to inline or not expand the function we specify at compile time. They are used as follows.
Static inline _ attribute__ ((noinline)) int func (); static inline _ attribute__ ((always_inline)) int func ()
Inline functions can be declared using inline, sometimes decorated with static and extern. Declaring an inline function with inline is the same as declaring a variable with the keyword register, except that the compiler is advised to expand inline at compile time. When using the keyword register to modify a variable, it is only recommended that the compiler put the variable in a register when allocating storage space to the variable, so that the program will run more efficiently. Will the compiler play it? The compiler has to make a tradeoff based on whether the register resources are tight and how frequently this variable is used.
Similarly, when a function is modified with the inline keyword, does the compiler necessarily expand inline at compile time? Not exactly. The compiler will also make decisions based on the actual situation, such as the size of the function body, whether there is a loop structure in the function body, whether there is a pointer, whether there is recursion, and whether the function calls are frequent. For example, the GCC compiler generally does not expand inline functions, and only when the compilation optimization option is turned on above-O2 will consider whether to inline expansion. When we use noinline and always_inline to declare a property on an inline function, the compiler's compilation behavior becomes certain. To use the noinline declaration is to tell the compiler not to expand; to use the always_inline attribute declaration is to tell the compiler to inline the expansion.
What is inline deployment? We have to talk about the basics of inline functions.
10.2 what is the inline function call cost
When it comes to inline functions, we have to talk about function call overhead. During the execution of a function, if you need to call other functions, it will generally execute the following procedure.
Save the current function jump to the calling function to restore the current function and continue to execute the current function
For example, in an ARM program, in a function F1 (), we process some data, and the results are temporarily stored in the R0 register. Next, you call another function, f2 (). After the call is over, you return to the F1 () function to continue processing the data. If we use the R0 register (used to hold the return value of the function) in the f2 () function, the value in the R0 register will be changed, and the temporary operation result in the F1 () function will be tampered with. When we return to the F1 () function to continue the operation, the result must be incorrect.
What are we going to do? Quite simply, before jumping to f2 () execution, save the value of the R0 register to the stack, and then restore the value in the stack to the R0 register after the execution of the f () function, so that the F1 () function can continue to execute as if nothing had happened.
This method proves to be OK, and modern computer systems, regardless of architecture and instruction set, use this method. Although it is a bit troublesome, it can at least solve the problem by spending more money and constantly saving and restoring the site, which is the cost of function calls.
Benefits of inline functions
There is no problem with this method for general function calls. But for some extreme cases, for example, a function is very small, there is only one line of code in the function body, and it is called frequently. If each call keeps saving the site, only to find that the function has only one line of code and wants to restore the site, it often results in high overhead and low performance-to-price ratio of the function. This is just like booking a table in a five-star hotel. VIP rooms, cutlery, air conditioning and service staff are all ready. when you arrive, you only order a bowl of noodles, wipe your mouth and leave after eating, and you do it three times a day. Do you think the waiter is bored?
The same is true of function calls. Some functions are small, frequently called, and expensive to call, so it is not cost-effective. We can declare this function as an inline function. When the compiler encounters an inline function during compilation, like a macro, it expands the inline function directly at the call. The advantage of this is to reduce the overhead of function calls, directly execute the code expanded by inline functions, and no longer have to save and restore the site.
10.3 inline functions and macros
Seeing this, some people may wonder, since inline functions are similar to macros, why not just define a macro instead of defining an inline function?
Existence is reasonable. Since inline function is widely used in C language, there is a reason for its existence. Over macros, inline functions have the following advantages.
Parameter type check. Although an inline function has the expansion property of a macro, its essence is still a function. During compilation, the compiler can still check its parameters, but macros do not have this function. Easy to debug. The debugging functions supported by the function include breakpoint and single step. Inline functions can also be used Return value. The inline function returns a value that returns a result to the caller. This advantage is relative to ANSI C. But now macros can also have return values and types, such as the one we defined using statement expressions earlier. Interface encapsulation. Some inline functions can be used to encapsulate an interface, but macros do not have this feature. 10.4 Compiler's processing of inline functions
As mentioned earlier, although we can declare a function as an inline function through the inline keyword, the compiler does not necessarily deal with this inline function. The compiler also needs to evaluate and weigh the pros and cons of deployment and non-deployment.
Inline functions are not flawless and have some drawbacks. For example, it increases the size of the program. If the inline function is called and expanded many times in a file, the volume of the whole program will become larger, which, to a certain extent, will reduce the addressing efficiency of CPU and the execution efficiency of the program. One of the functions of functions is to improve the reusability of code. We encapsulate some commonly used codes or code blocks into functions for modular programming, while inline functions often reduce the reusability of functions. Therefore, when the compiler expands the inline function, it not only detects whether there are pointers, loops and recursion inside the user-defined inline function, but also makes a tradeoff between function execution efficiency and function call cost. Generally speaking, to judge whether or not to expand an inline function, from the programmer's point of view, mainly consider the following factors.
The function is small and frequently called, and there are no recursions, loops and other statements in the function body. Whether the function itself is assigned as a function pointer is referenced elsewhere and whether the caller is in the same file.
When we think that a function is small and frequently called, and should be expanded inline, we can modify it with the static inline keyword. But whether the compiler will expand inline or not, the compiler will also have its own tradeoff. If you want to tell the compiler to expand, or not to expand, you can use noinline or always_inline to make a property declaration on the function.
/ / inline.cstatic inline _ attribute__ ((always_inline)) int func (int a) {return astat1;} static inline void print_num (int a) {printf ("% d\ n", a);} int main (void) {int I; i=func (3); print_num (10); return 0;}
In this program, we define two inline functions func () and print_num (), respectively, and then use always_inline to declare the properties of the func () function. Next, we disassemble the generated executable a.out, and the assembly code is as follows.
$arm-linux-gnueabi-gcc-o a.out inline.c$ arm-linux-gnueabi-objdump-D a.out 00010438: 10438: e92d4800 push {fp, lr} 1043c: e28db004 add fp, sp, # 4 10440: e24dd008 sub sp, sp, # 8 10444: e50b0008 str R0, [fp, #-8] 10448: e51b1008 ldr R1, [fp, #-8] 1044c: e59f000c ldr R0, [pc # 12] 10450: ebffffa2 bl 102e0 10454: e1a00000 nop (mov R0, R0) 10458: e24bd004 sub sp, fp, # 4 1045c: e8bd8800 pop {fp, pc} 10460: 0001050c andeq R0, R1, ip, lsl # 1000010464: 10464: e92d4800 push {fp, lr} 10468: e28db004 add fp, sp, # 4 1046c: e24dd008 sub sp, sp, # 8 10470: e3a03003 mov R3, # 3 10474: e50b3008 str R3, [fp #-8] 10478: e51b3008 ldr R3, [fp #-8] 1047c: e2833001 add R3, R3, # 1 10480: e50b300c str R3, [fp, # 12] 10484: e3a0000a mov R0, # 10 10488: ebffffea bl 10438 1048c: e3a03000 mov R3, # 010490: e1a00003 mov R0, R3 10494: e24bd004 sub sp, fp, # 4 10498: e8bd8800 pop {fp, pc}
As you can see from the disassembly code, because we declare the always_inline property of the func () function, the compiler expands directly at the call to the main () function when calling func () during compilation.
10470: e3a03003 mov R3, # 3 10474: e50b3008 str R3, [fp, #-8] 10478: e51b3008 ldr R3, [fp, #-8] 1047c: e2833001 add R3, R3, # 1 10480: e50b300c str R3, [fp, #-12]
As for the print_num () function, although we have declared it inline, the compiler does not expand it inline, but treats it as an ordinary function. Another detail to note is that when the compiler expands an inline function, it expands the code of the inline function directly at the call, instead of generating separate assembly code for the func () function itself. This is because other locations where the function is called have been expanded inline, so there is no need to generate it. In this example, we find that there is no separate assembly code for the func () function itself, the compiler only generates separate assembly code for the print_num () function.
Thinking: why are inline functions often decorated with static?
In the Linux kernel, you will see a large number of inline functions defined in the header file, often decorated with static.
Why are inline functions often decorated with static? This question has been discussed on the Internet for a long time, and it sounds reasonable, from C language to Clover, and some people even come up with the Linux kernel author Linus's explanation of static inline:
Static inline "means" we have to have this function, if you use it, but don't inline it, then make a static version of it in this compilation unit ". Extern inline "means" I actually have an extern for this function, but if you want to inline it, here's the inline-version ".
My understanding is this: why should inline functions be defined in the header file? Because it is an inline function and can be used like a macro, any source file that wants to use this inline function can be used like a macro without having to define it again and directly include the header file. Then why decorate it with static? Because we use inline functions defined by inline, the compiler does not necessarily expand inline, so when multiple files contain the definition of this inline function, it is possible to report a redefinition error at compile time. With static decorations, you can limit the scope of this function to their respective local files, avoiding redefinition errors. By understanding these two points, you will be able to understand most of the inline functions defined in the Linux kernel header file. As for some other inline function definitions, they have not been encountered very much, so I will not repeat them.
This tutorial is adapted from the C language embedded Linux Advanced programming Video tutorial No. 05, the electronic version of the book can join the QQ group: 475504428 download, more embedded video tutorials, you can follow:
Official account of Wechat: Otaku tribe (armlinuxfun)
51CTO College-Mr. Wang Litao: http://edu.51cto.com/sd/d344f
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.