In-depth understanding of the static keywords in the C language
In an interview, the interviewer asked me the difference between the static global variable and the global variable, although used before but did not carefully understand him, this time to study carefully.
Basic concepts
There are three cases of using static:
- function internal static variable
- function external static variable
- static function
The key to a static variable inside a function is that the life cycle is persistent, and his value does not disappear with the end of the function call, and the value of the static variable is retained for the next call, as well as the contents of the last call.
Static variables outside the function, as well as the static function, are key to the private nature, they belong only to the current file, and other files do not see them. For example:
/*test_static1.c*/#include<stdio.h>voidfoo () {}Static voidBar () {}inti =3;Static intj =4;intMainvoid) {printf ("%d \ n", i); printf ("%d \ n", J); return 0;}
/**/void foo () {}staticvoid bar () {}int 1; Static int 2;
Compiling two files together
GCC test_static1.c test_static2.c-o test_static
The compiler prompts you to:
/tmp/ccuerf9v.o:in function ' foo':test_static2.c: (. text+0x0): Multiple definition of ' foo ' '/tmp/cc9qncdw.o:test_static1.c: (. text+0x0): First definedhere/TMP/CCUERF9V.O: (. data+ 0x0): Multiple definition of ' I'/tmp/cc9qncdw.o: (. data+0x01 exit Status
Comment out the statement with the non-static variable I phase does not have this hint I repeat definition, because after using the static declaration, the variable is privatized, the same name variable in different files does not chong_tu each other.
The static function is similar to this, declaring a function as static, which means that we only use this function in the current file, and other files cannot be seen, and will not be chong_tu to each other, even if they have duplicate names.
Deep understanding
As a programmer we should not just be content to understand the phenomenon, but also to understand what is behind the phenomenon
Why the static variable inside the function is different from the normal function variable life cycle
Our program, compiled from source code, is delivered as an executable file, the executable is loaded into memory, and then executed. In the case of Linux programs, each Linux program has a runtime memory image. It can be understood as the distribution of data in memory when the program is running.
Figure 1 Linux Runtime memory image
When the program runs, the operating system creates the user stack, when a function is called, its arguments, local variables, return addresses, and so on, are pressed into the stack, and when the function is finished, the data is used by other functions, so the value of the local variable is not persisted after the function call ends. We'll zoom in on this area to see what's in the user stack.
Figure 2 Stack frame structure
Static variables, unlike ordinary local variables, are not persisted in the stack. Note In Figure A, there is an area, "Loaded from executable file", where there is a. data,. BSS, static variables are stored here, so the value of the static variable is retained after the function call ends. The. Data,. BSS area, executable file, and program compilation, linking, related.
First, multiple source code will be compiled into a relocatable target program, and then the linker will eventually build the executable target program. The relocatable target program is shown in Structure 3, as you can see, at this point,. data,. BSS, has appeared.
Figure 3 Relocatable Target Program
The. Data area stores the global C variables that have been initialized, and the. BSS store has no initialized global C variables, so these two zones are also called global zones. The compiler allocates space for each static variable in. data or. BSS.
The structure of the executable target program is shown in 4
Figure 4 Executing the target program
Comparing Figure 4 with Figure 1, you will find that part of the executable target program is loaded into memory, which is the source of "Loaded from executable file".
Also, from figure one, it can be seen that the memory space allocated by malloc is different from the function local variable, the static variable.
Why static variables and static functions outside the function are visible only to the inside of the file
To explain this problem, we must first understand the problem itself. The essence of this problem is that when we encounter a variable or function, where we go to find it, the static variable/function is different from how the normal variable/function looks.
Let's go back to just the example, this time, to carefully observe the message when compiling the link:
/*test_static1.c*/#include<stdio.h>voidfoo () {}Static voidBar () {}inti =3;Static intj =4;intMainvoid) {printf ("%d \ n", i); printf ("%d \ n", J); return 0;}
/**/void foo () {}staticvoid bar () {}int 1; Static int 2;
Compiling two files together
GCC test_static1.c test_static2.c-o test_static
The compiler prompts you to:
/tmp/ccuerf9v.o:in function ' foo':test_static2.c: (. text+0x0): Multiple definition of ' foo ' '/tmp/cc9qncdw.o:test_static1.c: (. text+0x0): First definedhere/TMP/CCUERF9V.O: (. data+ 0x0): Multiple definition of ' I'/tmp/cc9qncdw.o: (. data+0x01 exit Status
You will find that although we have only one command to compile links to two files, in fact, two source files are compiled separately into/TMP/CCUERF9V.O and/tmp/ CC9QNCDW.O, and, instead of appearing at compile time, the linker LD returns 1 when it appears at the link. Link is the two relocatable target program, grouped together, we found the variable i and Function foo definition appears chong_tu. The variable J and the function bar declared as static do not indicate chong_tu.
This means that when the LD is linked, some sort of check is needed to discover the chong_tu. The input of LD is the relocatable target file generated by each source file, so there must be some information in these target files, tell LD what variables they have, then LD can check if there is chong_tu.
Speaking 可重定位目标文件 of which, we have never explained why we should relocate. In fact, it's good to understand that when a source file is compiled, if the individual addresses in the generated target file are the end-of-run addresses, the addresses are likely to be chong_tu with the addresses in other files. Because when compiling a file, we do not know that there are other files, so the final address cannot be determined at compile time. Therefore, when you compile a single file, the address in the generated destination file starts at 0, and when linked, the linker repositions the addresses in the different destination files, resulting in an executable file. Note that the chong_tu here and the previous chong_tu is not the same thing, here the Chong_tu is different to relocate the same address in the target file Chong_tu, the previous paragraph is about the same name of the chong_tu between the variables.
At this point, we have to return to the format of the relocatable target file.
Figure 3 Relocatable Target Program
Note. Symtab section, this section stores the symbol table, assuming that the current relocatable target module is m, the symbol table will tell us the symbolic information defined and referenced in M, mainly divided into:
- M definition, and a global symbol that can be referenced by other modules: non-static function in M, non-static global variable.
- A global symbol defined by another module and referenced by M: a variable using extern declaration in M
- Local symbol only referenced by M: static function in M, static global variable.
Now compile and then look at the symbol table with the GNU Readelf tool.
$ gcc-c test_static1.c-o test_static1.o -S TEST_STATIC1.O
Symbol table'. Symtab'Contains theentries:Num:Value Size Type Bind Vis Ndx Name0:00000000 0notype LOCAL DEFAULT UND1:00000000 0FILE LOCAL DEFAULT ABS test_static1.c2:00000000 0Section LOCAL DEFAULT1 3:00000000 0Section LOCAL DEFAULT3 4:00000000 0Section LOCAL DEFAULT4 5:00000005 5FUNC LOCAL DEFAULT1Bar6:00000004 4OBJECT LOCAL DEFAULT3J7:00000000 0Section LOCAL DEFAULT5 8:00000000 0Section LOCAL DEFAULT7 9:00000000 0Section LOCAL DEFAULT8 Ten:00000000 0Section LOCAL DEFAULT6 One:00000000 5FUNC GLOBAL DEFAULT1Foo A:00000000 4OBJECT GLOBAL DEFAULT3I -: 0000000a +FUNC GLOBAL DEFAULT1Main -:00000000 0Notype GLOBAL DEFAULT UND printf
The data structure of the table is not explained and interested to see the extended reading section.
Now, if you are the linker ld, I give you 2 relocatable target programs, you get two symbols from the table, then you can check out the two symbol table whether there is chong_tu.
Because global symbols may define the same name, the linker has a set of rules to determine which symbol to choose. Symbols are divided into strong symbols and weak symbols.
- Strong symbols: Functions and global variables that have been initialized are strong symbols
- Weak sign: Uninitialized global variable is weak symbol
The rules for working with global symbols of the same name are:
- Multiple strong symbols are not allowed
- If there is a strong symbol, multiple weak symbols, then select strong symbol
- If there are multiple weak symbols, select one from the
Summarize:
1.static Global variables and global variables
Static global variable: Only valid for this file, can be used, this project other files are not visible, can not be used. stored in the global data area.
Global variables: Global variables as long as extern, it is valid for all files of this project.
2.static local variables and local variables
Static local variable: stored in the global data area, only valid for this function.
Local variables: stored in the local data area, only valid for this function.
3.static Functions and functions
The static function: The defined function is only visible to this file and is not visible to other files in this project and cannot be used.
Function: Can be called for this project, only this file is declared.
Common denominator: Static declaration once, if not changed so static value is always initialized value, if not at initialization time assignment, the system is assigned 0 by default. The value of this call is the last modified value.
The understanding of static in C language