McCabe’s Cyclomatic Complexity
In embedded software development, Cyclomatic Complexity is one of the most overlooked metrics. Yet, it’s one of the most powerful tools we have for writing reliable, maintainable firmware.
Cyclomatic Complexity measures the number of independent paths through a function. The higher the number, the harder the code is to test, understand, and maintain.
Here’s what it means to you:
-
The higher the complexity, the greater the chances of defects.
-
The higher the complexity, the greater the chances of introducing bugs when changing the code.
-
The measured complexity is the minimum number of test cases required to test the function.
Tools like pmccabe, Lizard, Understand, and cppcheck can calculate this automatically, giving you visibility into where your codebase is getting risky. Below is risk for a function with various complexity values:

Look at that last row. 51 and greater is untestable! That means if you have functions greater than 51, you cannot ensure no bugs in your code!
Curious about how these numbers relate to the risk of making code changes? Below is the risk of bug injection based on complexity value:

The risk jumps from 1 in 20 to 1 in 5 and progressively gets worse! The general rule of thumb is that your function complexity should be below 10. (Here’s why).
I used to write huge, complicated functions that did way too much. After using pmccabe (and other tools) daily, I naturally began writing small, clean, single-purpose functions. Now I use my CI pipeline to double-check myself, but I rarely write something over 10.
These measurements aren’t just about bugs though!
Here’s an expert tip: Cyclomatic Complexity tells you the minimum number of test cases you need to test that function! You should have at least that many tests!
If you’re writing unit tests, which I really hope you are, you should at least have the same number of test cases as your function complexity.
I use cyclomatic complexity as a sanity check to ensure that I have at least one test case for each path through a function.
Here’s a simple process to use Cyclomatic Complexity to improve your code:
-
Write your function (Yes, use TDD to drive production code development)
-
Run your cyclomatic complexity tool
-
Use a script or AI to analyze the results and point out issues
-
Identify what you can change and what you can do better next time
-
Clean-up your code (or dare I say use AI to help)
-
Commit your code
-
Let your pipeline verify everything is good
Cyclomatic Complexity isn’t about one more thing to do or vanity metrics. It’s about building firmware that’s predictable, testable, and easier to evolve over time. Add it to your toolbox if you haven’t done so already.