[ACCEPTED]-Why are drivers and firmwares almost always written in C or ASM and not C++?-c

Accepted answer
Score: 32

Because, most of the time, the operating 13 system (or a "run-time library") provides 12 the stdlib functionality required by C++.

In 11 C and ASM you can create bare executables, which 10 contain no external dependencies.

However, since 9 windows does support the C++ stdlib, most 8 Windows drivers are written in (a limited 7 subset of) C++.

Also when firmware is written 6 ASM it is usually because either (A) the 5 platform it is executing on does not have 4 a C++ compiler or (B) there are extreme 3 speed or size constraints.

Note that (B) hasn't 2 generally been an issue since the early 1 2000's.

Score: 27

Code in the kernel runs in a very different 24 environment than in user space. There is 23 no process separation, so errors are a lot 22 harder to recover from; exceptions are pretty 21 much out of the question. There are different 20 memory allocators, so it can be harder to 19 get new and delete to work properly in a kernel context. There 18 is less of the standard library available, making 17 it a lot harder to use a language like C++ effectively.

Windows 16 allows the use of a very limited subset of C++ in kernel drivers; essentially, those 15 things which could be trivially translated 14 to C, such as variable declarations in places 13 besides the beginning of blocks. They recommend 12 against use of new and delete, and do not have support 11 for RTTI or most of the C++ standard library.

Mac 10 OS X use I/O Kit, which is a framework based on 9 a limited subset of C++, though as far as 8 I can tell more complete than that allowed 7 on Windows. It is essentially C++ without 6 exceptions and RTTI.

Most Unix-like operating 5 systems (Linux, the BSDs) are written in 4 C, and I think that no one has ever really 3 seen the benefit of adding C++ support to 2 the kernel, given that C++ in the kernel 1 is generally so limited.

Score: 11

1) "Because it's always been that way" - this 35 actually explains more than you think - given 34 that the APIs on pretty much all current 33 systems were originally written to a C or 32 ASM based model, and given that a lot of 31 prior code exists in C and ASM, it's often 30 easier to 'go with the flow' than to figure 29 out how to take advantage of C++.

2) Environment 28 - To use all of C++'s features, you need 27 quite a runtime environment, some of which 26 is just a pain to provide to a driver. It's 25 easier to do if you limit your feature set, but 24 among other things, memory management can 23 get very interesting in C++, if you don't 22 have much of a heap. Exceptions are also 21 very interesting to consider in this environment, as 20 is RTTI.

3) "I can't see what it does". It 19 is possible for any reasonably skilled programmer 18 to look at a line of C and have a good idea 17 of what happens at a machine code level 16 to implement that line. Obviously optimization 15 changes that somewhat, but for the most 14 part, you can tell what's going on. In C++, given 13 operator overloading, constructors, destructors, exception, etc, it 12 gets really hard to have any idea of what's 11 going to happen on a given line of code. When 10 writing device drivers, this can be deadly, because 9 you often MUST know whether you are going 8 to interact with the memory manager, or 7 if the line of code affects (or depends 6 on) interrupt levels or masking.

It is entirely 5 possible to write device drivers under Windows 4 using C++ - I've done it myself. The caveat 3 is that you have to be careful about which 2 C++ features you use, and where you use 1 them from.

Score: 11

Except for wider tool support and hardware 13 portability, I don't think there's a compelling 12 reason to limit yourself to C anymore. I 11 often see complicated hand-coded stuff done 10 in C that can be more naturally done in 9 C++:

  • The grouping into "modules" of functions (non-general purpose) that work only on the same data structure (often called "object") -> Use C++ classes.
  • Use of a "handle" pointer so that module functions can work with "instances" of data structures -> Use C++ classes.
  • File scope static functions that are not part of a module's API -> C++ private member functions, anonymous namespaces, or "detail" namespaces.
  • Use of function-like macros -> C++ templates and inline/constexpr functions
  • Different runtime behavior depending on a type ID with either hand-made vtable ("descriptor") or dispatched with a switch statement -> C++ polymorphism
  • Error-prone pointer arithmetic for marshalling/demarshalling data from/to a communications port, or use of non-portable structures -> C++ stream concept (not necessarily std::iostream)
  • Prefixing the hell out of everything to avoid name clashes: C++ namespaces
  • Macros as compile-time constants -> C++11 constexpr constants
  • Forgetting to close resources before handles go out of scope -> C++ RAII

None of the C++ features described above 8 cost more than the hand-written C implementations. I'm 7 probably missing some more. I think the 6 inertia of C in this area has more to do 5 with C being mostly used.

Of course, you 4 may not be able to use STL liberally (or 3 at all) in a constrained environment, but 2 that doesn't mean you can't use C++ as a 1 "better C".

Score: 10

The comments I run into as why a shop is 18 using C for an embedded system versus C++ are:

  1. C++ produces code bloat
  2. C++ exceptions take up too much room.
  3. C++ polymorphism and virtual tables use too much memory or execution time.
  4. The people in the shop don't know the C++ language.

The 17 only valid reason may be the last. I've 16 seen C language programs that incorporate 15 OOP, function objects and virtual functions. It 14 gets very ugly very fast and bloats the 13 code.

Exception handling in C, when implemented 12 correctly, takes up a lot of room. I would 11 say about the same as C++. The benefit 10 to C++ exceptions: they are in the language 9 and programmers don't have to redesign the 8 wheel.

The reason I prefer C++ to C in embedded 7 systems is that C++ is a stronger typed 6 language. More issues can be found in compile 5 time which reduces development time. Also, C++ is 4 an easier language to implement Object Oriented 3 concepts than C.

Most of the reasons against 2 C++ are around design concepts rather than 1 the actual language.

Score: 7

The biggest reason C is used instead of 21 say extremely guarded Java is that it is 20 very easy to keep sight of what memory is 19 used for a given operation. C is very addressing 18 oriented. Of key concern in writing kernel 17 code is avoiding referencing memory that 16 might cause a page fault at an inconvenient 15 moment.

C++ can be used but only if the run-time 14 is specially adapted to reference only internal 13 tables in fixed memory (not pageable) when 12 the run-time machinery is invoked implicitly 11 eg using a vtable when calling virtual functions. This 10 special adaptation does not come "out of 9 the box" most of the time.

Integrating C 8 with a platform is much easier to do as 7 it is easy to strip C of its standard library 6 and keep control of memory accesses utterly 5 explicit. So what with it also being a 4 well-known language it is often the choice 3 of kernel tools designers.

Edit: Removed reference 2 to new and delete calls (this was wrong/misleading); replaced 1 with more general "run-time machinery" phrase.

Score: 7

The reason that C, not C++ is used is NOT:

  • Because C++ is slower
  • Or because the c-runtime is already present.

It 41 IS because C++ uses exceptions. Most implementations 40 of C++ language exceptions are unusable 39 in driver code because drivers are invoked 38 when the OS is responding to hardware interrupts. During 37 a hardware interrupt, driver code is NOT 36 allowed to use exceptions as that would/could 35 cause recursive interrupts. Also, the stack 34 space available to code while in the context 33 of an interrupt is typically very small 32 (and non growable as a consequence of the 31 no exceptions rule).

You can of course use 30 new(std::nothrow), but because exceptions 29 in c++ are now ubiqutious, that means you 28 cannot rely on any library code to use std::nothrow 27 semantics.

It IS also because C++ gave up 26 a few features of C :- In drivers, code 25 placement is important. Device drivers need 24 to be able to respond to interrupts. Interrupt 23 code MUST be placed in code segments that 22 are "non paged", or permanently mapped into 21 memory, as, if the code was in paged memory, it 20 might be paged out when called upon, which 19 will cause an exception, which is banned. In 18 C compilers that are used for driver development, there 17 are #pragma directives that can control 16 which type of memory functions end up on. As 15 non paged pool is a very limited resource, you 14 do NOT want to mark your entire driver as 13 non paged: C++ however generates a lot of 12 implicit code. Default constructors for 11 example. There is no way to bracket C++ implicitly 10 generated code to control its placement, and 9 because conversion operators are automatically 8 called there is no way for code audits to 7 guarantee that there are no side effects 6 calling out to paged code.

So, to summarise 5 :- The reason C, not C++ is used for driver 4 development, is because drivers written 3 in C++ would either consume unreasonable 2 amounts of non-paged memory, or crash the 1 OS kernel.

Score: 5

C is very close to a machine independent 9 assembly language. Most OS-type programming 8 is down at the "bare metal" level. With 7 C, the code you read is the actual code. C++ can 6 hide things that C cannot.

This is just my 5 opinion, but I've spent a lot of time in 4 my life debugging device drivers and OS 3 related things. Often by looking at assembly 2 language. Keep it simple at the low level 1 and let the application level get fancy.

Score: 3

Windows drivers are written in C++.
Linux 2 drivers are written in c because the kernel 1 is written in c.

Score: 2

Probably because c is still often faster, smaller 10 when compiled, and more consistent in compilation 9 between different OS versions, and with 8 fewer dependencies. Also, as c++ is really 7 built on c, the question is do you need 6 what it provides?

There is probably something 5 to the fact that people that write drivers 4 and firmware are usually used to working 3 at the OS level (or lower) which is in c, and 2 therefore are used to using c for this type 1 of problem.

Score: 2

The reason that drivers and firmwares are 58 mostly written in C or ASM is, there is 57 no dependency on the actual runtime libraries. If 56 you were to imagine this imaginary driver 55 written in C here

#include <stdio.h>

#define OS_VER   5.10
#define DRIVER_VER "1.2.3"

int drivermain(driverstructinfo **dsi){
   if ((*dsi)->version > OS_VER){
       (*dsi)->InitDriver();
       printf("FooBar Driver Loaded\n");
       printf("Version: %s", DRIVER_VER);
       (*dsi)->Dispatch = fooDispatch;
   }else{
       (*dsi)->Exit(0);
   }
}

void fooDispatch(driverstructinfo *dsi){
   printf("Dispatched %d\n", dsi->GetDispatchId());
}

Notice that the runtime 54 library support would have to be pulled 53 in and linked in during compile/link, it 52 would not work as the runtime environment 51 (that is when the operating system is during 50 a load/initialize phase) is not fully set 49 up and hence there would be no clue on how 48 to printf, and would probably sound the death 47 knell of the operating system (a kernel 46 panic for Linux, a Blue Screen for Windows) as 45 there is no reference on how to execute 44 the function.

Put it another way, with a 43 driver, that driver code has privilege to 42 execute code along with the kernel code 41 which would be sharing the same space, ring0 40 is the ultimate code execution privilege 39 (all instructions allowed), ring3 is where 38 the front end of the operating system runs 37 in (limited execution privilege), in other 36 words, a ring3 code cannot have a instruction 35 that is reserved for ring0, the kernel will 34 kill the code by trapping it as if to say 33 'Hey, you have no privilege to tread up 32 ring0's domain'.

The other reason why it 31 is written in assembler, is mainly for code 30 size and raw native speed, this could be 29 the case of say, a serial port driver, where 28 input/output is 'critical' to the function 27 in relation to timing, latency, buffering.

Most 26 device drivers (in the case of Windows), would 25 have a special compiler toolchain (WinDDK) which 24 can use C code but has no linkage to the 23 normal standard C's runtime libraries.

There 22 is one toolkit that can enable you to build 21 a driver within Visual Studio, VisualDDK. By all 20 means, building a driver is not for the 19 faint of heart, you will get stress induced 18 activity by staring at blue screens, kernel 17 panics and wonder why, debugging drivers 16 and so on.

The debugging side is harder, ring0 15 code are not easily accessible by ring3 14 code as the doors to it are shut, it is 13 through the kernel trap door (for want of 12 a better word) and if asked politely, the 11 door still stays shut while the kernel delegates 10 the task to a handler residing on ring0, execute 9 it, whatever results are returned, are passed 8 back out to ring3 code and the door still 7 stays shut firmly. That is the analogy concept 6 of how userland code can execute privileged 5 code on ring0.

Furthermore, this privileged 4 code, can easily trample over the kernel's 3 memory space and corrupt something hence 2 the kernel panic/bluescreens...

Hope this 1 helps.

Score: 1

Perhaps because a driver doesn't require 3 object oriented features, while the fact 2 that C still has somewhat more mature compilers 1 would make a difference.

Score: 1

There are many style of programming such 9 as procedural, functional, object oriented 8 etc. Object oriented programming is more 7 suited for modeling real world.

I would use 6 object-oriented for device drivers if it 5 suites it. But, most of the time when you 4 programming device drivers, you would not 3 need the advantages provided by c++ such 2 as, abstraction, polymorphism, code reuse 1 etc.

Score: 1

Well, IOKit drivers for MacOSX are written 44 in C++ subset (no exceptions, templates, multiple 43 inheritance). And there is even a possibility 42 to write linux kernel modules in haskell.)

Otherwise, C, being 41 a portable assembly language, perfectly 40 catches the von Neumann architecture and 39 computation model, allowing for direct control 38 over all it's peculiarities and drawbacks 37 (such as the "von Neumann bottleneck"). C 36 does exactly what it was designed for and 35 catches it's target abstraction model completely 34 and flawlessly (well except for implicit 33 assumption in single control flow which 32 could have been generalized to cover the 31 reality of hardware threads) and this is 30 why i think it is a beautiful language.) Restricting 29 the expressive power of the language to 28 such basics eliminates most of the unpredictable 27 transformation details when different computational 26 models are being applied to this de-facto 25 standard. In other words, C makes you stick 24 to basics and allows pretty much direct 23 control over what you are doing, for example 22 when modeling behavior commonality with 21 virtual functions you control exactly how 20 the function pointer tables get stored and 19 used when comparing to C++'s implicit vtbl 18 allocation and management. This is in fact 17 helpful when considering caches.

Having said 16 that, object-based paradigm is very useful 15 for representing physical objects and their 14 dependencies. Adding inheritance we get 13 object-oriented paradigm which in turn is 12 very useful to represent physical objects' structure 11 and behavior hierarchy. Nothing stops anyone 10 from using it and expressing it in C again 9 allowing full control over exactly how your 8 objects will be created, stored, destroyed 7 and copied. In fact that is the approach 6 taken in linux device model. They got "objects" to 5 represent devices, object implementation 4 hierarchy to model power management dependancies 3 and hacked-up inheritance functionality 2 to represent device families, all done in 1 C.

Score: 0

because from system level, drivers need 4 to control every bits of every bytes of 3 the memory, other higher language cannot 2 do that, or cannot do that natively, only 1 C/Asm achieve~

More Related questions