55

I realize this may be subjective, so will ask a concrete question, but first, background:

I have always been an embedded software engineer, but usually at Layer 3 or 2 of the OSI stack. I am not really a hardware guy. I have generally always done telecoms products, usually hand/cell-phones, which generally means something like an ARM 7 processor.

Now I find myself in a more generic embedded world, in a small start-up, where I might move to "not so powerful" processors (there's the subjective bit) - I cannot predict which.

I have read quite a bit about debate about exception handling in C++ in embedded systems and there is no clear cut answer. There are some small worries about portability and a few about run-time, but it mostly seems to come down to code size (or am i reading the wrong debates?).

Now I have to make the decision whether to use or forego exception handling - for the whole company, for ever (it's going into some very core s/w).

That may sound like "how long is a piece of string", but someone might reply "if your piece of string is an 8051, then don't. If, OTOH, it is ...".

Which way do I jump? Super-safe & lose a good feature, or exceptional code and maybe run into problems later?

9
  • 4
    Embedded systems are different from desktop systems. Generally, you focus of producing them cheaper rather than more performant.
    – Anon.
    Commented Feb 9, 2010 at 1:51
  • 5
    I suppose that kind of depends on what the embedded app is. Smartphones are one thing, but I think I'd still like my elevator controllers to be long on reliability and short on language feature coverage
    – Jherico
    Commented Feb 9, 2010 at 1:53
  • 3
    Having worked on a few embedded systems using C++, I would say don't use C++ at all, let alone exceptions. All the stuff C++ does behind your back in the runtime is a giant pain to debug. The first time an app programmer makes a call to an OS primitive in a static object's constructor you'll be in a world of hurt (__cpp_initialize() being called before your operating system init, perhaps).
    – Carl Norum
    Commented Feb 9, 2010 at 1:54
  • 11
    @Carl Norum: that's not an argument against C++, it's an argument against running code before entering main. Commented Feb 9, 2010 at 10:40
  • 2
    You have to run code before entering main. Where else does the stack come from? I'm not sure I get what you're saying.
    – Carl Norum
    Commented Feb 9, 2010 at 21:32

7 Answers 7

27

In terms of performance, my understanding is that exceptions actually reduce the size and increase the performance of the normal execution paths of code, but make the exceptional/error paths more expensive. (often a lot more expensive).

So if your only concern is performance, I would say don't worry about later. If today's CPU can handle it, then tomorrows will as well.

However. In my opinion, exceptions are one of those features that require programmers to be smarter all of the time than programmers can be reasonably be expected to be. So I say - if you can stay away from exception based code. Stay away.

Have a look at Raymond Chen's Cleaner, more elegant, and harder to recognize. He says it better than I could.

3
  • 4
    I think Jon Kalb's exception safe coding guidelines pretty successfully address the problem of telling the difference at a glance between what Raymond calls 'bad' and 'not-bad' exception safe code. (Although Raymond's 'not-bad' code still looks bad to me because it's using naked-new.) They also mean that you don't have to 'check every single line of code,' as Raymond says.
    – bames53
    Commented Mar 21, 2014 at 23:57
  • John, I can't readily agree that exceptions reduce the size of the code. I've seen data (presented by the IAR) where use of exceptions has bloated the code by tens of percent, compared to the same code without exceptions. Commented Oct 27, 2017 at 16:07
  • Re the cited article by Chen: I suspect that it's very outdated, due to things like RAII and smart pointers. I doubt that anyone could get a job as a C++ programmer today without knowledge of RAII. (They certainly couldn't if I were doing the interviewing, and over the last five or six years, I've only had to reject one or two candidates because they didn't know RAII. Commented Dec 11, 2023 at 15:43
14

The most problem with exceptions -- they don't have predictable time of execution. Thus they are not suitable for hard real-time applications (and I guess most embedded application doesn't fall in this category).

The second is (possible) increasing of binary's size.

I would propose you reading of Technical Report on C++ Performance which specifically addresses topics that you are interested in: using C++ in embedded (including hard real-time systems) and how exception-handling usually implemented and which overhead it has.

1
  • A nugget from the technical report: "because the constructors of the Standard Library exception classes [..] require an argument of type std::string, this overhead may be included in a program inadvertently". A lot of exceptions use std::string, and this means dynamic memory allocation. Avoiding dynamic memory allocation also means avoiding memory leaks, which is highly useful in embedded applications. Commented May 18, 2017 at 13:07
12

The choice of whether to use exceptions or not should really lie with whether they are going to fit your program's problem domain well or not.

I've used C++ exceptions extensively, both in retrofitting into old C code, and in some newer code. (HINT: Don't try to re-fit 20 year old C code that was written in a low memory environment with all manner of inconsistent exceptions. It's just a nightmare).

If your problem is one that lends itself to handling all the errors in one spot (say, a TCP/IP server of some sort, where every error condition is met with 'break down the connection and try again'), then exceptions are good - you can just throw an exception anywhere and you know where and how it will be handled.

If, on the other hand, your problem doesn't lend itself to central error handling, then exceptions are a ROYAL pain, because trying to figure out where something is (or should be) handled can easily become a Sisyphean task. And it's really hard to see the problem just by looking at the code. You instead have to look at the call trees for a given function and see where that function's exceptions are going to end up, in order to figure out if you have a problem.

5

I think the problem is that many people voice their opinion without having a solid understanding of how exception handling in C++ works.

I have recently started at a new company, and there is consensus that we should not use exceptions, because we can't test them, because nondeterministic behaviour, etc etc. All wrong, of course.

When we talk about the overhead of having exception handling used in the code, we need to carefully consider overhead on top of what? Granted it comes at a cost, but that is the cost of alternative? Say we are using return error codes. In such scenario HALF of the if() statements in the source code will be dedicated to testing error codes and forwarding them up the call stack. Not making this up, actual metric of the codebase I'm looking at. And most of it is to deal with a) events that can't pretty much ever happen, like not having memory at the start of an embedded application and b) events that if they actually happen, we can not do anything about anyway, other than shutdown.

In this case introduction of exception handling would significantly reduce complexity of the code, separating handling of rare events from the business as usual logic. And saves ton's of overhead, because the error code checking is happening all the time. Further, it significantly reduces the size of the code. Think how much effort is needed to propagate error codes up the stack through 10 different functions, until we get somewhere where we can officially bail. Using the exception handling you can bypass the 10 intermediary levels of functions, and go straight to where we can deal with it.

4

I'd say use exceptions appropriately if the runtime environment supports them. Exceptions to handle extraordinary conditions are fine, and can cause little overhead depending on the implementation. Some environments don't support them, especially in the embedded world. If you ban them, be careful to explain why. I once had a guy that, when told not to use exceptions, did a divide by zero instead. Not exactly what we had in mind.

3

I usually consider two use cases that guide when exceptions should be used and how they should be implemented

  1. Sanity checks which are both important and useful for development (both initial and evolutionary) - essentially these should never happen in mission ready code, and can be compiled out if necessary.
  2. Real mission time checks with real mission type recovery (depending on your application, retry, degraded functionality, or warn and disable)

There are several alternative techniques:

  1. C-style status return value or parameter. This has a heavy impact on code readability, especially when it involves nested ifs. The real logic of a function can be overwhelmed by error checking if/elses or multiple returns from a function that are considered a no-no, especially if there is wrap up code such as undoing a lock at the function exit.

  2. C++ exceptions - eliminates the readability problems of the c style status, but adds an extra architectural design effort to decide which level of the architecture should generate and handle the exceptions. This needs to be done with C-style status values as well, but C has a slight engineering advantage since the status is visible in the API, and forces the programmer at every level to decide what to do with the status. If you see in the API that there is a return status, then as a minimum think about what values it can have (hopefully well documented), consider if it can happen and what you can do about it. With C++, exception throwing is less visible - you can't even see the status value return or parameter value.

  3. A compromise (which I still need to try) is to use C++ exceptions within a function - i.e. throw anywhere in a function where in C you would set and return a status - and use a catch at the end of the function so that you have a single exit (i.e. to release a lock) - that eliminates nested elses, and/or multiple returns in the code.

If you have an architectural design for how to design pass and handle exceptions around - great go for it - if you don't then using C++ exceptions is much neater and probably more robust than C style nested ifs and/or multiple function exits.

1

I'm doing a lot on ESP32S3 these days. It all boils down to whether you can accept the performance impact. The legend of toll free exception handling may be true for PCs, but on embedded systems it's a myth:

On my ESP32S3 each invocation of try/catch gives you a performance hit of very few nanoseconds, however code that actually throws may bring at least an additional 400µs(!) to the table.

While this is completely unacceptable for IRQ service routines, I'd be wary of it also in driver code and everything that is executed frequently.

1
  • 1
    Conincidentally, I just picked up ESP32 again after a few years away. I fully intend to use exception handling, at least in the main applciation (I am just reading a sensor once a second, or less freequntly). Thanks for your answer
    – Mawg
    Commented Dec 12, 2023 at 14:12

Not the answer you're looking for? Browse other questions tagged or ask your own question.