Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

C and Functional Safety in the Automotive Industry (Part III): Mind Your Language

DZone's Guide to

C and Functional Safety in the Automotive Industry (Part III): Mind Your Language

Watch your language! Check out this post to learn more about C++ and its success in embedded systems due to increased safety and efficiency.

· IoT Zone ·
Free Resource

In the previous posts, we took a look at the rise of C as the dominant language for safety-critical embedded systems. Then, we will examine some of the pitfalls that programmers fall into when using such a powerful tool. There is a growing need to be unusually self-reliant in terms of anticipating safety concerns in compiling and runtime environments.

In this post, we’ll take a further look at institutions and practices that focus on a C subset’s clarity and readability, as well as the challenges that this aspect of programming contains.

Avoiding Language Constructs That are Prone to Human Errors

Many software bugs appear because the code is written in an unstructured way, using a poor or non-scalable design. In such cases, only a couple of incremental changes can transform the project into ungovernable spaghetti code.

Another source of potential issues is the more or less obfuscated code sometimes enjoyed by geek programmers; these are things like packing several expressions, statements, and calls onto a single line for the sake of maximizing code visibility on your screen. Obviously, these are aspects that have to be avoided in developing functional, safe software.

The rule of thumb here is to maximize transparency and make the code easy to read, understand, and review by others. In this respect, there are several powerful constructs provided by C that should be avoided as much as possible. Preprocessor directives, pointer arithmetic, and typecasting are just a few of them.

MISRA C standardized a very detailed set of rules to help developers reduce the risks of using error-prone coding patterns. One essential tool in regards to code clarity is the project’s coding guidelines. If MISRA C is an official standard shared by different industries, the coding guidelines are an organization/project-specific document intended to address stylistic or conventional aspects that won’t necessarily be related to the language subset, but will help to cohere the team’s efforts and expectations for how the code is to be structured and documented. Such guidelines will usually include naming conventions, code file structure, coding layout, and even comment documentation formats.

Strong Typing

Returning to MISRA C, it’s notable that this industry-oriented branch of C programming language enforces strong guidelines and restrictions intended to minimize error-prone coding patterns.

Strong typing is not really enforced in C, but is one of the best practices in safety-critical systems, in order to avoid issues caused by loss of value, loss of sign, or loss of precision. Therefore, MISRA C provides a number of rules for moving C closer to a more strictly-typed methodology.

Firstly, it decrees that implicit type casting is avoided in order to prevent accidental and undesirable casts. Next, the explicit type casts need to be limited to cases where the entire information of the value is preserved. For example, this could include permitting integers and floats to be converted only to wider types, whilst preserving the original signs of any affected integers.

MISRA C also rules that function-like preprocessing macros be avoided, since, among other reasons, they do not allow parameter type checking. Another forbidden practice is unions usage, because of the risk that data may be misinterpreted.

Limited Usage of Pointers

Pointers are one of the key features in C and are hard to avoid entirely in any real-life application. In the context of C, ISO 26262 casts constraints for enforcing strong typing and also stipulates that pointer to integer conversions (and the other way around) is forbidden. Furthermore, additions and subtractions are the only mathematics that pointers are permitted to undertake during operations that involve array indexing.

Preprocessor Directives

Another nice feature of C is macros, which are considered to be on ‘the dark side’ with respect to safety-critical systems. The possibility to define, redefine, and undefine them at any moment can easily lead to confusion with respect to the existence or meaning of a macro.

Enabling or disabling code blocks by preprocessing macro directives can also lead to code that is hard to read, opening the gates for dead code or strange control flows.

Function-like macros also have to be avoided, for the reasons previously mentioned, in regards to strong typing. Fortunately, in this case, the inline functions represent a much better alternative.

Coding Layout

Though the coding layout is outside the scope of MISRA C (which defers projecting or organization specific coding guidelines, as mentioned above), it, nonetheless, has a couple of rules for addressing the structure of standard C constructs.

Examples of rules in this category include:

  • If constructs shall always be followed by a compound statement (i.e. a statement block in braces), switch constructs should always have a default clause.
  • For loop counters and control variables, they must fulfill a set of rules regarding where and how they are initialized, modified, or checked.
  • Parentheses should be used for emphasizing operator priority in expressions.

Data Flow Consistency Enforcement

This aspect is generally derived from the design in regards to those few features in C that support concepts such as data encapsulation and modularity. The best practice advises developers to use unique identifiers to avoid ambiguity about the meaning of a variable, to minimize the visibility of a variable to the relevant scope only, and to use const for read-only variables.

Control Flow

Though constraints related to control flow are not specific to C, two basic rules also considered to be best practice are: not to use unbounded recursions, since they represent a high risk of generating stack overflows; and to ensure that a function concludes in only single possible exit point. Though the latter guideline is intended to promote better readability, it has since come a question for a tendency to lead to deeper if-block trees, which, in themselves, make code harder to read.

That’s it for this look at the pre-eminent place of C (and its subset) over nearly fifty years into the embedded software sector. Opinions might differ as to whether its dominance in the field is due to a luxurious legacy infrastructure from decades of development, or because it’s still the best and most powerful tool for the job after all these years. But, in an increasingly locked-down software development world, C still represents the power that accompanies responsibility.

Topics:
automotive ,c ,c++ ,embedded development

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}