7 tips for writing portable C code
Writing software in C that is portable and reusable is quickly becoming a critical activity in the world of embedded software. But portable C Code doesn’t happen by accident; it requires intent and much forethought. There are seven tips that developers can follow to help ensure that their software is better suited for portability.
Tip #1 – Use a module level API
Defining a module level API can be critical to whether C code will be portable or not. The module level API defines what the module does along with what its inputs and outputs are. In my earlier blog 10 Tips for designing a HAL, I discussed the process that a developer would follow to define a hardware abstraction layer. Many of those HAL tips can also be applied to defining a C module's API and should be followed to help ensure that a C code module can be reused.
Tip #2 – Minimize module coupling
When porting code, there is nothing more painful than trying to bring in code that is tightly coupled. Tightly coupled code is great because it has few dependencies on external C modules. The greater the coupling, though, the more modules that need to be brought into the new code and, as a result, the longer and more painful the process. Tightly coupled code can also cause ROM bloat as unnecessary code comes in with the necessary code. Developers with their sights on portable and reusable code should try to minimize how many external modules their code is dependent on.
Tip #3 – Encapsulate
One of the key concepts of object oriented design is to encapsulate. Encapsulation can be understood as information hiding. The idea is that a module developer should only expose the variables and functions that an external user needs to access the module's behavior. Everything else should be hidden so that another developer that doesn’t fully understand the code doesn’t accidentally shoot themselves in the foot. The best way in C to encapsulate is to use the keyword static heavily. Functions and variables by default are implicitly extern. To help hide internal functions and variables the static specifier can be used to limit their scope and essentially hide the data.
Tip #4 – Use ANSI-C
Many compilers have intriniscs or extensions that are designed to help out a developer by providing capabilities that are not defined within the ANSI-C standard. The problem with using these capabilities, many of which use #pragma, is that they are compiler-specific. An attempt to move from one compiler to the next will result in compiler errors and the potential for software bugs to creep in depending on the added capability used. Developers interested in portable and reusable code should limit themselves to ANSI-C or even strict ANSI-C compilations.
Tip #5 – Define a C style guide
The use of a C style guide may not seem very important when developing portable code. After all, a developer never really knows whether the code will ever be reused and if it is, the code may be ported into a code base that has a completely different style. Further, company C style guides tend to evolve over time and with employee turnover. But the whole point of using a style guide, even if it will be different in the future, is to ensure that the code at least follows a common convention. That convention will make the code more easily readable and understandable by a future developer tasked with importing the code into a new project whenever it does happen.
Tip #6 – Document the code well
One of my least favorite activities is inheriting code that contains little structure or documentation as to what it is supposed to be doing. In a perfect world, there would be at least five different aspects included in all code documentation. The first would be a basic requirements document defining what the module is supposed to be doing in the first place. Second, there should be design documentation and models of the code demonstrating how it works. Third, the original developers’ thoughts and assumptions about how the implemented code works should be provided. Fourth is a list of key parameters and algorithm specifics along with critical areas that could break down when porting or modifying the software. Finally, there should be actual code comments that follow allow with the actual C code. An added bonus would be to receive documentation of module level unit tests, how they were performed, and any associated results.
Tip #7 – Avoid bit fields
Just because a feature exists in C doesn’t mean that it will port easily between compilers. The C standards have nebulous areas where the compiler vendor can choose how they want to implement the standard. Probably one of the most well-known of these nebulous areas concerns bit fields. Compilers have the decision making on where bits will be ordered and even as to the endianness of the final bit field.
Bit fields in theory can be portable but it really depends on how the programmer plans on using them. Accessing the field using bit manipulations or masks can result in completely unexpected behavior between two different compilers. Developers should therefore make sure that they fully understand the holes in the C standard and how to protect their code.
In today's fast paced development environment, developing portable and reusable C code is quickly becoming a must for every development team. The seven tips presented here are just the tip of the iceberg. To learn more about writing portable and reusable code in C, consider attending my free online class Writing Portable and Robust Firmware in C. Part of the Continuing Education Center program offered by EDN's sister publication Design News, the class runs for five daily one-hour sessions, starting August 31.
Jacob Beningo is a Certified Software Development Professional (CSDP) whose expertise is in embedded software. He works with companies to decrease costs and time to market while maintaining a quality and robust product. Feel free to contact him at email@example.com, at his website www.beningo.com, and sign-up for his monthly Embedded Bytes Newsletter here.
Join over 2,000 technical professionals and embedded systems hardware, software, and firmware developers at ESC Minneapolis Nov 4-5, 2015 and learn about the latest techniques and tips for reducing time, cost, and complexity in the embedded development process.
The Embedded Systems Conference and EDN are owned by UBM Canon.