C/C++ Usage of 'static' for Global and Local Variables
Category Programming Techniques
1. What is 'static'?
The 'static' is a commonly used modifier in C/C++, used to control the storage method and visibility of variables.
1.1 Introduction of 'static'
We know that variables defined within a function are allocated space on the stack by the compiler when the program executes to their definition. The space allocated on the stack for a function is released when the function execution ends, which raises a question: if you want to preserve the value of this variable in the function until the next call, how can this be achieved? The most straightforward method that comes to mind is to define it as a global variable, but defining a global variable has many drawbacks, the most obvious of which is the destruction of the variable's scope of access (making the variable defined in this function not only controlled by this function). The 'static' keyword can solve this problem well.
In addition, in C++, when a data object is needed to serve the entire class rather than a specific object, while also striving not to break the encapsulation of the class, that is, when this member needs to be hidden inside the class and not visible to the outside, it can be defined as a static data member.
1.2 Storage of Static Data
Global (Static) Storage Area: Divided into the DATA segment and the BSS segment. The DATA segment (initialized global area) stores initialized global variables and static variables; the BSS segment (uninitialized global area) stores uninitialized global variables and static variables. It is automatically released when the program ends. The BSS segment is automatically cleared to 0 by the system before the program is executed, so uninitialized global variables and static variables are already 0 before the program is executed. Variables stored in the static data area are initialized at the very beginning of the program and are the only ones initialized.
The internal implementation mechanism of 'static' in C++: static data members must exist at the very beginning of the program. Since functions are called during the program execution, static data members cannot be allocated space and initialized within any function.
Thus, there are three possible places for its space allocation: first, as the external interface header file of the class, where there is a class declaration; second, the internal implementation of the class definition, where there are class member function definitions; third, the global data declaration and definition before the main() function of the application.
Static data members need to actually allocate space, so they cannot be defined in the class declaration (only data members can be declared). The class declaration only declares the "size and specifications" of a class and does not actually allocate memory, so it is wrong to write a definition in the class declaration. It also cannot be defined outside the class declaration in the header file, because this will cause multiple definitions in the source files that use the class.
'static' is introduced to inform the compiler to store the variable in the program's static storage area instead of the stack space. Static data members are initialized in the order they are defined, and attention should be paid to the initialization of nested static members. The order of elimination is the reverse of the initialization order.
Advantages: It can save memory because it is shared by all objects, so for multiple objects, static data members are only stored in one place for all objects to share. The value of the static data member is the same for each object, but its value can be updated. As long as the value of the static data member is updated once, it ensures that all objects access the same updated value, which can improve time efficiency.
2. The Role of 'static' in C/C++
2.1 In General
(1) When modifying variables, static local variables are initialized only once and extend the life cycle of the local variables until the program ends.
(2) When a global variable is modified by 'static', this global variable can only be accessed within this file and cannot be accessed in other files, even if it is declared externally with 'extern'.
(3) When a function is modified by 'static', this function can only be called within this file and cannot be called by other files. Variables modified by 'static' are stored in the static variable area of the global data area, including both global static variables and local static variables, and are allocated memory in the global data area. They are automatically initialized to 0.
(4) When you don't want to be released, you can use 'static' to modify it. For example, modify the array stored in the stack space in the function. If you don't want this array to be released after the function call ends, you can use 'static' to Point pt; pt.output(); }
Press **Ctrl+F7** to compile without errors, but when generating the EXE program by pressing F7, a linker error is reported.
error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA) ```
This is because the static member variable of the class must be initialized before use.
Add int Point::m_nPointCount = 0;
before the main() function and recompile to link without errors, and the program will output 1 when run.
Conclusion 5: The static member variable of the class must be initialized before it is used.
Thought Summary: Static resources belong to the class but exist independently of it. From the perspective of the class loading mechanism of J, static resources are loaded when the class is initialized, while non-static resources are loaded when the class object is instantiated. The initialization of the class is earlier than the instantiation of the object, such as the Class.forName("xxx")
method, which initializes a class but does not instantiate an object, only loading the static resources of this class. So for static resources, it is impossible to know which non-static resources are in a class; but for non-static resources, it is different, because they are produced after the object is instantiated, so they can recognize the things that belong to the class. So the answers to the above several questions are very clear:
1) Can a static method refer to non-static resources? No, things that are produced when an object is instantiated do not recognize static resources that exist after initialization.
2) Can a static method refer to static resources? Yes, because they are all loaded when the class is initialized, and everyone knows each other.
3) Can a non-static method refer to static resources? Yes, non-static methods are instance methods, which are produced after the object is instantiated, so it recognizes all the content that belongs to the class.
(static modifier for class: This is used relatively less than the previous usage. Generally, static cannot modify a class. If static modifies a class, it indicates that the class is a static inner class (note that static can only modify an inner class), that is, an anonymous inner class. The four rejection mechanisms of the thread pool ThreadPoolExecutor, CallerRunsPolicy, AbortPolicy, DiscardPolicy, DiscardOldestPolicy, are static inner classes. The content of static inner classes will be specifically discussed when writing inner classes.)
3.3 Summary:
(1) Static member functions cannot call non-static members.
(2) Non-static member functions can call static members. Because static members belong to the class itself and exist before the object of the class is produced, static members can be called in non-static member functions.
(3) Static member variables must be initialized before use (such as
int MyClass::m_nNumber = 0;
), otherwise, an error will occur during the linker.
General Summary: In the class, static can be used to modify static data members and static member methods.
Static Data Members
(1) Static data members can achieve data sharing among multiple objects. They are shared members of all objects of the class, occupying only one space in memory. If the value is changed, the value of this data member in each object is changed.
(2) Static data members are allocated space when the program starts running and are released after the program ends. As long as the class specifies static data members, space will be allocated for static data members even if the object is not defined.
(3) Static data members can be initialized, but they can only be initialized outside the class body. If the static data member is not assigned an initial value, the compiler will automatically initialize it to 0.
(4) Static data members can be referenced either by the object name or by the class name.
Static Member Functions
(1) Static member functions, like static data members, belong to the class's static members, not object members.
(2) Non-static member functions have a this pointer, while static member functions do not have a this pointer.
(3) Static member functions are mainly used to access static data members and cannot access non-static members.
Here is an example of using the class's static member variables and functions to deepen understanding. This example creates a student class, where each object of the student class will form a doubly linked list, using a static member variable to record the head of this doubly linked list, and a static member function to output this doubly linked list.
Example
```c
include <stdio.h>
include <string.h>
const int MAX_NAME_SIZE = 30;
class Student { public: Student(char *pszName); ~Student(); public: static void Printf