Embedded development, especially in os-less microcontroller programs, often suffers from the rampant use of global variables.This phenomenon is common among programmers transitioning from early assembly language and beginners, who tend to treat global variables almost like function parameters.They define numerous chaotic structures in .h files, declare a bunch of externally visible global variables that are quite overwhelming, and then assign values like 123 in one module while making decisions based on that value in another module.Whenever I see such programs, I can’t help but frown and slam the table in anger.Yes, I mean it, in anger.While I do not deny the importance of global variables, I believe they should be used with extreme caution; their misuse can lead to more severe structural system issues.
Why Should Global Variables be Minimized?They can lead to unnecessary constants being used frequently, especially when these constants are not properly defined with macros, making the code extremely difficult to read.They can cause unreasonable software layering; global variables act as a shortcut, blurring the boundaries between the “device layer” and the “application layer” for programmers.Lower-level programs may mistakenly focus on higher-level applications.This can indeed be efficient during the early stages of software system construction, with rapid debugging progress, but later on, it often results in a plethora of bugs and patches everywhere.It would not be an exaggeration to say that it feels like a struggle to survive.Due to the unreasonable software layering, even minor modifications or deletions of features during later maintenance often require extensive changes across most modules,and the original code comments are often forgotten to be updated.At this point, the system handed over to later maintainers resembles a “quagmire,” where comments only serve to add more confusion above the mire.The extensive use of global variables inevitably leads to some variables lingering between interrupts and the main loop.If not handled properly, the system’s bugs will appear randomly and erratically, revealing the early signs of a terminal illness; without a strong expert to save the day, it is doomed to a slow death.Needless to say, you have successfully created a malformed system,which exists in a mysterious state of stability!You look at this machine, and the machine looks back at you, both silent, with a sense of unease in your hearts.You are uncertain when it will crash or when the next complaint will arise.What are the Consequences of Extensive Use of Global Variables?“The veteran” is proud because the system cannot function without him; he knows all the “danger zones” like the back of his hand.When an urgent bug arises, only he can resolve it.You cannot only not fire him, but you also have to give him a raise.Newcomers face a quick demise; anyone hired to maintain this system, apart from creating more bugs, typically leaves within a month, spreading the word about the poor software quality of this company.As the product undergoes subsequent upgrades, the original creator, who has not interacted with the system for months, will find that he has forgotten many of the danger zones, leading to increasingly longer maintenance cycles for product upgrades,because modifying one feature will trigger many bugs, and fixing one bug will lead to the emergence of even more bugs.During this time, even more global variables will be created.Eventually, he tells the boss, “It’s no good, it’s no good, we don’t have enough resources; RAM or flash space is too small, we need to upgrade.”Customer complaints are incessant, after-sales support is on the verge of collapse, and salespeople are hesitant to recommend this product,leading to a shrinking market share and a deteriorating company image.
To Address This, There Are Only Two PrinciplesMinimize the use of global variables whenever possible; I believe that apart from system states, control parameters, communication handling, and some efficiency-critical modules, most can be resolved through reasonable software layering and programming techniques.If it is unavoidable to use them, hide them as deeply as possible.
- If only a certain .c file uses it, make it static to that file, and also include the structure definitions;
- If only one function uses it, make it static within that function;
- If it must be exposed for reading, use a function to return it, thus making it read-only;
- If it must be modified, fine, I will provide a function interface for you to pass parameters for assignment;
- If extern must invade me, I can still strictly control which objects include my .h file, rather than letting it be publicly visible in includes.h, causing embarrassment.
Thus, you can understand how deeply I feel about global variables; unfortunately, I have had to rewrite all those cases that the “veterans” handed over to me for maintenance.Final NoteGlobal variables are unavoidable; almost every device’s lower level needs them to record the current state and control timing.However, they should not be used to pass parameters, which is highly discouraged.Try to limit the scope of variables to the module using them; if other modules need access, provide read or write function interfaces to strictly control access.This principle is similar to the private attributes in C++,which is also beneficial for future program debugging.The reason C has a ++ version is largely to control its flexibility; the object-oriented concept has long existed in C and can also be implemented.When the number of global variables in a module exceeds three (inclusive), it is better to encapsulate them in a structure,so they can be reset together, preventing loss of track.Declaring a static global variable or global array within a function does not occupy stack space,but some compilers may place large global arrays in a different address space than regular variables.If using Keil C51, since it is statically compiled, stack overflow will trigger an alarm, so you can freely use it, just be mindful of the traffic rules.In os-less systems of microcontrollers, where only the stack is used without heap usage, those “startup.s” files that allocate heap space can boldly remove the heap space.Program models? How to analyze and abstract them? From which angle should the model be constructed? I would love to hear opinions from netizens.I have always analyzed systems from two perspectives: event-state machine transition diagrams and data flow diagrams; the former analyzes control flow and improves UI, while the latter reveals the origins and fates of system data.These theories are covered in the “Software Engineering” textbooks in universities, and everyone might as well refer to them. However, those theories ultimately originate from managing large system software, so they need to be tailored for smaller applications.Material sourced from Engineer’s Progress Notes, works belong to the original author, for learning reference only~
Finally
The author has collected some embedded learning materials; reply with【1024】 in the public account to find the download link!
Recommended good articles Click the blue text to jump to the link
☞ Collection | Comprehensive Guide to Linux Application Programming
☞ Collection | Learn Some Networking Knowledge
☞ Collection | Handwritten C Language
☞ Collection | Handwritten C++ Language
☞ Collection | Experience Sharing
☞ Collection | From Microcontrollers to Linux
☞ Collection | Power Control Technology
☞ Collection | Essential Mathematics for Embedded Systems
☞ MCU Advanced Collection