element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Personal Blogs
  • Community Hub
  • More
Personal Blogs
Legacy Personal Blogs It's dangerous to go alone! Take MISRA-C
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: chriswhite
  • Date Created: 6 May 2015 2:35 AM Date Created
  • Views 2300 views
  • Likes 1 like
  • Comments 2 comments
  • c
  • programming
  • thelinker
  • code
  • misra-c
  • linker
  • embedded.fm
  • software
Related
Recommended

It's dangerous to go alone! Take MISRA-C

chriswhite
chriswhite
6 May 2015

This post was written by chriswhite.

 

In last article I posted here (“Be Excellent to Each Other”) I wrote about how a little compassion and respect for the future can make a big difference for code quality. I purposely avoided many specifics to focus more on the motivations for taking greater care with our work. This week, I’d like to address something very specific and perhaps something that could form a foundation for writing better code.


image

On last week’s episode of embedded.fm with software professional Andrei Chichak, we talked about MISRA-C. Now, that may sound like a disease or vitamin supplement, but it’s actually a comprehensive set of guidelines for using the C programming language. MISRA stands for the “Motor Industry Software Reliability Association”, a group founded by the British auto industry in the late 90’s for the purpose of improving robustness and reliability in vehicle software.

 

The particular industry doesn’t matter though: reliable and robust code should be a goal for everyone writing software. Thus guidelines like MISRA-C can provide a good starting point for your own personal (or organizational) coding standards. Unfortunately, the MISRA-C documents are not free and open, so I can’t directly quote rules here. However, I can talk about some similar coding standards for which your tools might already test with the right options turned on, and, which in most cases, overlap with MISRA.

 

Check for Uninitialized variables (-Wuninitilized in gcc)

 

How is an uninitialized variable handled in your particular language? Even if you know, it’s probably not wise to rely on implicit behavior as it is easy to forget how it works. In C there are different behaviors depending on where the variable declaration occurs. It’s trivial to make a mistake of habit when there are subtle differences like that. For instance, the following code contains a big bug:

 

// Return the pointer to the first instance of ch in str

char *find_char(char ch, char *str, uint16 length)

{

    char *ptr;

 

    for (index = 0; index < length; index++) {

        if (ch == str[index]) {

           ptr = &str[index];

           break; 

        }

    }

    return ptr;

}


What happens if ch does not occur in str? Well, the return value is going to be undefined. Now, this example is contrived, and there are lots of ways to implement this without the intermediate variable. However, at a cursory glance, it may not be obvious there’s a problem here because it is easy to see that the code works for everything but the error case. Unit tests might catch this, if you remember to test the wrong path as well as the right ones.

 

Remember, the issue with C is complicated by the different behavior depending on where the variable is declared. For example, a minor change to this code will work just fine (the first time!):

 

 

// Return the pointer to the first instance of ch in str

char *find_char(char ch, char *str, uint16 length)

{

     static char *ptr;

 

     for (index = 0; index < length; index++) {

         if (ch == str[index]) {

             ptr = &str[index];

             break; 

         }

     }

     return ptr;

}

 

In C, normal variables allocated on the stack (within functions) are uninitialized and will have whatever value the stack memory held at the time of declaration. Static variables (those declared outside functions (aka globals) or within functions with the static keyword) are implicitly initialized to zero if they don’t have another initialization value. This inconsistency is what leads to errors. You probably wouldn’t make this a static (but if you were writing a strtok like function, you can see how locals vs statics and globals might be confusing.

 

In C++, object members variables are also uninitialized, which might be even more unexpected to developers coming from other OOP languages.

 

When in doubt, explicitly set your variables to a value. In fact, skip the when in doubt part.

Your compiler can help you out too in case you forget, turn on the warning for uninitialized variables and it will keep you out of trouble.

 

Implicit type conversion/promotion (integer promotion, usual arithmetic conversions)

 

A common theme throughout all the MISRA rules is to avoid implicit behavior. Not only is it not portable, experience tells us that’s where many errors creep into systems.

 

There are lots of operations in C that result in some conversion between types if the compiler isn’t told what to do. Those conversions are governed by a complex set of rules that I challenge any developer to rattle off the top of their heads.

 

One of the worst and subtlest offenses in this class of bugs is conversion between signed and unsigned. For example:

 

int32_t a = -1;

uint32_t b = 1;

printf(“%d”\n”, a < b);

 

Don’t look it up, think about what happens. Stumped? If you answered 1 or true, think again. Still stumped? Well don’t feel bad, it’s really subtle. Notice that we are dealing with two different types, signed and unsigned integers. Perhaps your intuition tells you that C would be sensible and convert b to a signed integer to evaluate the comparison. What really happens is the C compiler  converts a to an unsigned and since a’s real value in hex is 0xFFFFFFFF, that’s a really big number.

 

Your intuition has run aground on the rocks of C’s arcane implicit behavior. If you are sensing a trend here, it’s intentional: many of MISRA’s rules attempt to supersede implicit actions by demanding that you ask for what you really want.

 

Use standard types

 

This is a big one, and if you are like me and learned C back in the 80’s and early 90’s, you might habitually use int, short, char, etc. as your basic data types. You might also have some notion that each of those types are always the same size (int’s are 4 bytes, shorts 2, and chars are 1, right?).

 

In the embedded world, and especially if you are writing portable code, this can cause a lot of trouble. The interpretation of these basic types is often up to the compiler and architecture. Thus, chars can be both signed and unsigned. Integers can vary in size from 16 to 64-bits. Mix this confusion with the implicit type promotion rules and you can set yourself up for disaster.

 

Include <stdint.h> and explicitly ask for the storage size and signedness you desire. Use typecasts on the right-side elements (rvalues) of expressions to make sure that the compiler is promoting types in a way you want.

 

Use parentheses judiciously (and avoid operator precedence problems)

 

As a recovering math major, I like to think I have a good handle on how arithmetic operator precedence. You know, things like 4*5 + 10*5 and knowing that the multiplications will be performed first. C has a way of humbling all of us self-described smarty-pantses. Here’s an example that tripped me up recently:

 

int Z = X + Y << 2;

 

Now, I have this unfortunate habit of treating right and left shift operators (<<, >>) as multiplies and divides by factors of 2 in my mind. Thus, one would think the shift should be evaluated first, since it’s equivalent to a divide. In actuality, C puts a lower precedence on the shift operator than addition and subtraction. So X+Y is evaluated first, then shifted. Oops.

 

You can either try to remember things like this, or you can once again be explicit:

 

int Z = X  + (Y << 2);

 

Problem solved, and I think in a way that is far more readable. If you forget this one, you may be lucky enough to get a compiler warning (gcc did in fact warn me by default when I tried the first example, while IAR did not). Turn it on if you have it available, but also just put parentheses everywhere, they are free.

 

image

           

Don’t use Goto/continue

 

Just don’t.

 

Summary

A lot of these things come down to a few simple ideas:

  • Be explicit, especially where implicit rules might be confusing
  • Avoid language features that are ambiguous or unexpected.
  • Avoid assumptions about the underlying platform.
  • Turn on all the warnings you can and make warnings equal errors in your compiler to keep yourself honest.

 

If you would like to use the actual MISRA-C rules in your projects, there a few ways to go about it, some of which may already be available to you depending on your tools. IAR, for example has the ability to statically check your code against the entirety of the MISRA rule set:

image

 

You can also purchase the MISRA C documentation from MISRA at http://www.misra.org.uk. As of this writing, it is £15 for a pdf copy.

 

You will probably find a subset of the rules more applicable to your particular needs than the entire collection. Some are very constraining (particular when working close to the hardware), and as our guest Andrei pointed out, you can still be compliant with MISRA while not using every rule by noting deviations. Having any rules at all is a big step up for some of us, and is often the first step toward quality code.

 

Some useful resources for safe C programming:


Books:

  • C Traps and Pitfalls by Andrew Koenig
  • Safer C by Les Hatton

 

Software:

 

  • PC-Lint from Gimpel Software. A static analysis tool that can check for MISRA compliance and more.

 

Documentation:

 

  • The official MISRA website
  • Sign in to reply
  • Former Member
    Former Member over 9 years ago

    Actually the MISRA C rules are not as comprehensive as some believe. In fact they came about almost by accident. In spring 1997 software engineers at the then Austin Rover Group (ARG) sent a draft C coding standard for review by Programming Research (PRL). At the time I was PRL's senior consultant and was asked to undertake the review. I considered the rules in the ARG draft inadequate and suggested a replacement set. The review report was duly sent off to ARG and PRL got paid for the review. A few months later ARG sent a further document to PRL. It had my recommended rules in it but it was marked not as a revised ARG standard but as version 0.1 of the MISRA C rules. Version 1 of MISRA C slightly weakened those rules but they were essentially based on what I had suggested in my three-day review. All MISRA did was to write accompanying text around them.

     

    I never intended what I wrote to be used in that way. The rules I proposed were what I considered a bare minimum (and they have since been weakened further). MISRA C is not IMO the great accomplishment that some represent it as. I no longer participate in the MISRA C Working Group because as far as I can see, it is unable collectively to demonstrate a robust grasp of what language subsetting is actually for, leave alone how it should be done. It is in fact technically quite straightforward to define the language restrictions in a metalanguage such that parser generation techniques could be used to generate a checker automatically from the metalanguage rules. My impression is that a certain tool vendor represented on the working group found this rather alarming and wanted to suppress it. This, of course, is one of the conflicts of interest that can always arise in standardisation by sectoral bodies.

     

    Even the best MISRA C checkers can't match the quality of checking that, say, the SPARK examiner does for Ada. That's because SPARK was designed with a specific set of verification processes in mind. The SPARK tools can now check over 100,000 lines of Ada overnight to *prove* freedom from run-time errors in all possible executions. With the right tools you can do *almost* as good for C as SPARK can do for Ada, but you need a language subset draconianly stricter than what I originally suggested. You also need proof annotations tailored to the verification algorithms you need to use. I see no clear sign that the MISRA C Working Group collectively acknowledges this - and much suggestive evidence that some commercial interests want to keep it that way.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Former Member
    Former Member over 10 years ago

    I was not having such deep knowledge for working on PC-Lint. With the help of this post I came to know various things about this software. Thanks for sharing.More such information about marketing surveys is available here .

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube