MISRA C Compliance: A Practical Guide for Firmware Teams

Understand the rules, the tooling, and the workflow changes needed to achieve MISRA C compliance without halting your development velocity.

By

Software Development Experts

UpNext Software is a full-cycle software development company specialising in embedded systems, IoT, mobile, and web development.

MISRA C Compliance: A Practical Guide for Firmware Teams
Article Contents

A firmware team we talked to had shipped a motor controller for three years without incident. Then a customer in the industrial safety space asked for a MISRA C compliance report as a condition of the contract. The team ran a static analyser over the codebase for the first time and got back roughly 14,000 findings. Panic followed. Six weeks later they had a clean gate in CI and a compliance summary they could hand over — and they had changed almost none of the working logic.

That gap between "14,000 violations" and "actually fine" is what this guide is about. MISRA C is far more tractable than the first analyser run suggests, provided you understand what the standard is asking for, which rules genuinely change how you write code, and how to stage the work so your roadmap doesn't stall.

What MISRA C actually is — and what it isn't

MISRA C is a set of coding guidelines for the C language, published by the MISRA consortium, aimed at avoiding constructs that are undefined, unspecified, implementation-defined, or simply easy for humans to misread. It grew out of automotive practice but is now used across aerospace, medical devices, rail, industrial automation and defence.

A few structural facts that matter more than any individual rule:

  • The guidelines split into <strong>Directives</strong> — things a tool cannot fully check, like "implementation-defined behaviour shall be documented" — and <strong>Rules</strong>, which are checkable against source code.
  • Each guideline has a category: <strong>Mandatory</strong>, <strong>Required</strong>, or <strong>Advisory</strong>. Mandatory guidelines cannot be deviated from at all. Required ones can be deviated with a documented, approved rationale. Advisory ones are recommendations you may disapply project-wide.
  • Rules are also classified as <strong>decidable</strong> or <strong>undecidable</strong>. Decidable rules can be answered definitively by a tool. Undecidable ones — anything touching runtime values or reachability — cannot, which is why some findings are unavoidably approximate.
  • Analysis scope is either <strong>single translation unit</strong> or <strong>system</strong>. System-scope rules need the whole build, not one file at a time. This has real consequences for how you wire up CI.
  • MISRA C:2012 is the edition most teams still name in contracts. MISRA C:2023 consolidates it with the subsequent amendments and technical corrigenda and covers C90 through C18. Check the current publication list before you quote an edition in a contract.

What MISRA is not: a security standard, a substitute for testing, or a guarantee of correctness. It won't catch a wrong control algorithm or a race condition in your scheduler. If your concern is security specifically, CERT C and the MISRA addendum that maps guidelines to ISO/IEC TS 17961 are the more relevant reading.

Do you actually need full compliance?

We'll say this plainly because most vendors won't: a lot of teams asking about MISRA don't need certified compliance. They need better code.

If nobody is contractually or regulatorily requiring it, and you're not going through a functional safety assessment, the honest advice is to skip the compliance artifacts and take the engineering value instead. Turn on aggressive compiler warnings and treat them as errors. Add a free checker with a MISRA-oriented ruleset. Adopt the twenty or thirty rules that catch real bugs — the essential type model, uninitialised reads, switch structure, unused return values — and ignore the paperwork entirely. You will get most of the defect reduction for a fraction of the cost.

You do need real, documented compliance when:

  • A customer or tier-one supplier makes it a deliverable.
  • You're building an argument for IEC 61508, ISO 26262, IEC 62304 or a similar functional safety standard, where coding standards are an expected part of the evidence.
  • You're supplying into a supply chain where your code will be audited by someone who has never met you.

The rules that actually change how you write code

Most of a first-run violation count is noise: missing braces, implicit conversions, comment style. Bulk-fixable. The rules that force design decisions are a much shorter list.

The essential type model

The rules in section 10 define a type model on top of C's own, and they will generate more findings than anything else. Mixing signedness, assigning a wider type to a narrower one, using a character type in arithmetic, relying on integer promotion — all flagged. The fixes are mechanical but numerous, and they surface genuine bugs surprisingly often, particularly around bit manipulation of peripheral registers.

Dynamic memory and recursion

Rule 21.3 prohibits the standard allocation functions. Rule 17.2 prohibits recursion, direct or indirect. If your codebase leans on malloc at runtime or has a recursive parser buried in a protocol stack, this is architectural work, not a cleanup pass. Static pools, fixed-size buffers and explicit iterative state machines are the usual answer — and they're better practice on a constrained MCU regardless.

Pointer conversions

Section 11 constrains conversions between pointer and integer types and between incompatible pointer types. Embedded C is built on exactly these conversions — memory-mapped registers, DMA descriptors, casting a byte buffer to a packed struct. You won't eliminate them. You'll isolate them into a small, reviewed, deviated hardware abstraction layer, which is where they belonged anyway.

Third-party and vendor code

Vendor HALs, RTOS kernels and middleware stacks are almost never MISRA-clean. The MISRA Compliance guidance handles this through the concept of <strong>adopted code</strong>: code you did not write, brought in as-is, assessed separately from your own. You classify it, decide whether it's modified or unmodified, and document how it is treated. What you must not do is silently exclude it from analysis and hope the auditor doesn't ask.

Choosing and configuring the tooling

No tool checks every guideline. Directives and undecidable rules require process and review. Any vendor claiming 100% automated coverage is overselling.

Broadly there are three tiers. Commercial MISRA-focused analysers — Helix QAC, LDRA, PC-lint Plus, Parasoft, Polyspace, Coverity — offer high rule coverage, per-rule traceability and the compliance reports auditors expect. Open-source options, principally Cppcheck with its MISRA addon, cover a useful subset for free and are excellent for the "engineering value, no certificate" path. Compiler warnings and clang-tidy overlap with some rules but were never designed against the standard.

Two configuration points get missed constantly:

  • <strong>Feed the tool your real build.</strong> Same include paths, same preprocessor defines, same target word sizes, same compiler dialect. Analysis of a differently-configured build is analysis of a program you don't ship. A compile_commands.json from your build system is the cleanest way to do this.
  • <strong>Decide suppression policy up front.</strong> In-code suppression comments are traceable and reviewable in diffs; external suppression files are tidier but drift silently as code moves. Pick one, write it down, and don't let individual developers invent their own.

The compliance artifacts nobody budgets for

Clean analyser output is not compliance. The MISRA Compliance guidance defines the documents that constitute a compliance claim, and producing them is real work that teams routinely forget to schedule:

  1. <strong>Guideline Enforcement Plan</strong> — for every guideline, how it is checked. Tool, tool configuration, manual review step, or a statement that it cannot be checked and why.
  2. <strong>Guideline Recategorisation Plan</strong> — where you have moved a guideline's category. You may make Advisory rules stricter or disapply them; you may not weaken Mandatory ones.
  3. <strong>Deviation Records</strong> — each accepted violation of a Required guideline, with rationale, scope, and evidence that safety and correctness are unaffected.
  4. <strong>Guideline Compliance Summary</strong> — the top-level table stating, guideline by guideline, whether you comply, comply with deviations, or have disapplied it.

Generate these from your toolchain rather than maintaining them by hand. A spreadsheet updated manually is out of date within a sprint and becomes the weakest part of your audit.

A workflow that doesn't halt velocity

The failure mode is always the same: someone declares a compliance sprint, the team stops shipping features, morale drops, and half the fixes get reverted later because they broke behaviour. Here's the approach that works instead.

<strong>Baseline, don't boil the ocean.</strong> Run full analysis once and record every finding as an accepted baseline. Zero code changes on day one. You now have a number that can only go down.

<strong>Gate on the diff.</strong> CI fails a pull request if it introduces a violation in changed lines. New code is compliant from the moment the gate goes in; old code is grandfathered. This single change stops the problem growing while you shrink it.

<strong>Ratchet the baseline.</strong> Each sprint, retire a slice — one rule family, or one module. Essential type conversions and brace/structure rules first, because they're mechanical and reduce the count fast. Architectural items like recursion and dynamic allocation go on the roadmap as proper stories with test coverage attached.

<strong>Run analysis locally, not only in CI.</strong> A developer who learns about a violation twelve minutes after pushing has already moved on. Pre-commit hooks or an editor integration for the fast decidable rules keep the feedback loop tight. Reserve the slow whole-program system-scope analysis for nightly builds.

<strong>Review deviations as a group, weekly, briefly.</strong> Two engineers and a fifteen-minute slot. Deviations approved individually and privately are how a codebase ends up with four hundred of them and no coherent rationale.

Deviations done properly

A good deviation record explains the engineering, not the inconvenience. "Cast required to access memory-mapped peripheral register at fixed address defined by the device datasheet; address validated against linker script; access confined to hal_gpio.c" is defensible. "Refactoring is too risky" is not — and it is the first thing an auditor will pull on.

Keep deviations narrow in scope. A file-level suppression is better than a project-level one; a line-level one is better still. Group repeated identical deviations under a single documented rationale rather than duplicating the text, and re-review the whole set before each release. Deviations that outlive the code they were written for are technical debt with a paper trail.

Where teams get stuck

In our experience the technical rules are rarely the blocker. The blockers are organisational: nobody owns the compliance artifacts, the tool licence covers one seat so analysis never reaches CI, or the codebase has no build abstraction so the analyser can't be configured to match the real target. Fix those three and the rest is steady, predictable work.

If you're standing at the start of this — a contract requirement landed, or an audit is scheduled, and your codebase has never seen a MISRA checker — the useful first step is a scoped baseline assessment: run the analysis properly configured, classify the findings, and get a realistic estimate of effort split between mechanical cleanup and architectural change. That's a week or two of work, not a quarter, and it turns an unbounded worry into a plan.

We work with firmware teams on exactly this kind of engagement, and on longer-running embedded projects where an extended engineering team handles the compliance workstream alongside feature development. You can see the range of systems work we've delivered in our portfolio. If you'd like to talk through your codebase, your target standard and what a sensible sequence looks like, get in touch — we're happy to give you a straight answer, including if that answer is that you don't need full compliance at all.

Continue Reading
Related Articles