The Increasing Use of C++ in Embedded Linux Development

Follow our official account to keep receiving embedded knowledge!

In embedded Linux projects, should we develop in C or C++?

I think it depends on the preferences and expertise of the lead developer.

The Increasing Use of C++ in Embedded Linux Development

Here is a popular topic in the embedded field on Zhihu; let’s see what the experts say:

The Increasing Use of C++ in Embedded Linux Development

Original link:

https://www.zhihu.com/question/374663834

Several highly upvoted responses:

Respondent: pansz

The reality is: C++ is too complex, and embedded talent is already scarce. If you also need someone who can use C++ without causing issues, that number is even smaller.

So using C is indeed mainstream, as the requirements for C programmers are lower.

I remember when I first started with embedded systems, the system didn’t even have an MMU, and all the code was in a single memory space. I had to manage the memory pool myself to avoid fragmentation. A random memory access error could affect completely unrelated modules. Would you dare to use C++ in such a system?

Conclusion: If you are developing code alone and are confident in your C++ skills, then using C++ is certainly fine. However, considering the overall C++ proficiency of the programmer community compared to C, using C for embedded projects is more realistic.

Respondent: candy

As an embedded veteran with over ten years of experience, I can say that C++ is too complex. It has too many language features, and implementing a function can be done in dozens of ways, with many bizarre methods to achieve a function. The complexity of C++ means that without over five years of experience, you won’t be able to use it well. If a project team has varying levels of C++ skills, using some strange features to implement functions makes maintenance impossible among team members.

During debugging, object-oriented debugging is best done with graphical tools, which are mostly unavailable in embedded systems. Writing business logic in C++ and debugging later can be a nightmare; debugging C++ in embedded systems is an order of magnitude more complex than C.

While C has fewer features, it is entirely sufficient. There aren’t many ways to implement a function; you can learn it in about a year and become proficient in three years, while with C++, you might not even grasp its features in three years. C can be used simply or complexly; C with classes, small classes, and structures with pointers can easily be implemented. Look at the Linux kernel, the kernel header files, structures, macros, and various ingenious usages, and you will find that C++ is completely redundant. C++ suffers from complexity. Experienced teams in large companies using C++ only use a subset of its features.

The many design features of C++ are not an advantage but a disadvantage. Don’t be fooled by the fact that it supports almost every feature; too many choices actually mean no choice. A good language has only one way to implement a function, like Python or Go.

In the application layer, the business logic is what matters. The various complex business logics can become chaotic with too many language features. C is entirely sufficient, and various design patterns can also be implemented in C.

One can absorb some excellent features from the kernel, such as the kernel’s bidirectional linked list, some structures, macros, logging, memory management, thread management, inter-thread and inter-process communication, and various locks. These need to be encapsulated in C. Learning these things is essential to say you have mastered C. Even for beginners, having an advanced C programmer can guide a group of novices in writing business code. However, an advanced C++ programmer cannot lead a group of beginners to complete the same project.

Resource and efficiency constraints mean that for the same business function, C has lower memory usage and higher speed than C++. These things are readily available in C++, but they are bulky and have many dependencies, making them too heavy for embedded environments. This means that for the same product, using C allows for lower-end main control chips and smaller memory, resulting in lower BOM costs compared to using C++, giving a significant competitive advantage.

Respondent: Listening to the heartbeat

The mainstream compilation language for microcontrollers will likely remain a combination of C and a small amount of assembly for the foreseeable future. In my view, the future of embedded Linux leans towards a mixed programming paradigm, with kernel modules using C and application layer logic using a mix of C++, Python, and Node.js, while the interface uses Java and QT/C++. Here’s why.

In the microcontroller field, C++ is not very popular due to historical reasons and industrial demand. Microcontrollers have evolved from the 51 architecture, and the mainstream flash capacity is still around 64KB to 256KB.

The current capacity limitations make it difficult to apply C++ features like templates, generic programming, and STL in development. However, if we do not use these and only use C++ that supports classes, there is no urgent need to switch from C to C++, especially when C has structures and function pointers that can replace it. The promotion of Python and JS faces similar challenges, compounded by debugging difficulties.

However, for Rust, this reasoning does not apply. Due to historical inertia, many companies, large and small, still have a significant amount of legacy and ongoing C language projects (including original factory solutions). Replacing them with Rust is a commercial cost issue rather than a language issue (in my view, Rust is far superior to C at the language level). Therefore, Rust enthusiasts should focus on providing open-source projects for mainstream vendor platforms (specific projects, not just porting a hello world) rather than advocating for the superiority of syntax.

Moreover, the advantages of microcontrollers are not just real-time control but also cost-effectiveness. For devices with production volumes in the tens or even hundreds of thousands, flash capacity is a significant cost. Therefore, the industry prefers to do the most with the least cost. In this regard, C has a clear advantage over C++, Python, and JS.

In the embedded Linux field, C++ is undoubtedly one of the main players in the application layer. Although QT/C++ is gradually being replaced by Android/Java due to improved chip performance, it still occupies a mainstream position in fields such as medical, industrial control, and vehicle navigation. This is also one of the important application areas for C++. Saying that embedded systems are challenging and that C++ is also very difficult gives a one-sided impression that embedded personnel learn C++ less.

Additionally, the challenging aspects of C++ include move semantics, template specialization, lambdas, and template metaprogramming. The various syntactic combinations of C++ can seem like a foreign language if one does not spend a lot of time studying them (with few exceptions). However, in the industrial sector, especially for embedded applications, using STL encapsulated vectors, maps, and algorithms for convenience, and encapsulating some template functions or classes for reuse, often means that many of C++11’s new features go unused. To say it is difficult is somewhat exaggerated.

The industrial challenge is always how to translate product requirements into specific task breakdowns (balancing performance, cost, and functionality while ensuring long-term stability), rather than which language to use to implement tasks. When demand drives any language, whether Python, JS, C++, or Java, programming for salary means that as long as there is demand, someone will step into that direction. Difficulty is not the issue; demand and salary are the issues.

Respondent: idea4good

Let’s start with the conclusion:

  1. C++ is very useful in embedded systems and microcontrollers;
  2. C with classes is fully capable of handling most development tasks, and if used well, it can significantly improve your code quality (in the embedded field, I personally do not encourage STL and templates, which I will discuss later).

GuiLite, with only 5,000 lines of code, is a commonly used GUI framework in embedded systems and microcontrollers. It is written in C++ and has 4.8K stars on GitHub and 2K stars on Gitee. You might wonder what can be done with 5,000 lines? It can not only handle regular interface elements but also perform 3D operations on microcontroller platforms, integrate with web pages to present interface effects in web form, and of course, support VR effects. Recently, it has also integrated with FFmpeg to support video playback without dependencies. There’s no need for more words; the images speak for themselves:

The Increasing Use of C++ in Embedded Linux Development
The Increasing Use of C++ in Embedded Linux Development
The Increasing Use of C++ in Embedded Linux Development
The Increasing Use of C++ in Embedded Linux Development
The Increasing Use of C++ in Embedded Linux Development
The Increasing Use of C++ in Embedded Linux Development

This is not to say that GuiLite is exceptionally powerful, but to illustrate the charm of the C++ language. If C were used instead of C++, at least tens of thousands of lines would be needed to achieve the same effect. Remember the famous Einstein bug equation? A little more code can significantly increase the number of bugs.

GuiLite is a typical example of C with classes. Many may think this is very basic, but this is precisely the original intention behind the invention of C++. This feature allows you to completely say goodbye to function pointers; of course, many C experts have implemented all C++ features using function pointers.

First, kudos to the experts, but as ordinary developers, we must understand that the cost is a large number of function pointers. The presence of many function pointers greatly reduces code readability, while C with classes can elegantly eliminate all function pointers. Although you may think it is low-level, it can significantly reduce your code size. Moreover, it has excellent support from compilers; any microcontroller compiler can support this simple C++ feature.

If you have read the Linux virtual file system code, what repeatedly interrupts your understanding of the code? The answer is function pointers. To support multiple file systems, Linux is heavily using function pointers in its code. If inheritance and virtual functions were used instead, the code could be greatly simplified.

This is the cost of implementing inheritance and virtual functions in C. You might say: Linux’s method is efficient! The answer is: it is not. No matter how you optimize at the C language level, it cannot compare to optimizations at the compiler level.

As developers, programming philosophy is far more important than syntactic sugar. C with classes represents a progress in programming philosophy, even though it is trivial in terms of syntactic difficulty. Remember, I am talking about programming philosophy; even such simple syntax is still misused, completely disregarding actual needs, starting with a class without considering the original intention of class invention.

Classes require you to restructure code at a high level, but you use them to pollute every detail, every line of code. Again, if used well, 5,000 lines can solve many problems; if used poorly, it is better not to use them at all. Stick to the language you are most proficient in to pollute your code; that way, the pollution is more efficient, right?

Finally, are STL and templates suitable for embedded systems? Personally, I think they are not very suitable. First, this poses a significant challenge to the compiler. Windows and Linux platforms are not an issue, but in microcontroller environments, compatibility issues may arise. Additionally, templates and STL are not very friendly for debugging and are not suitable for embedded and microcontroller development environments where the running cost (steps) is relatively complex.

The invention of STL and templates was not intended for embedded systems and microcontrollers. Therefore, forcing their use will bring you many troubles. The best environment for STL and templates is large-scale “games.” This set of tools is a typical product of trading space for time. Many impressive games require minimal CPU and memory resources, thanks to their contributions, but the cost is that your code will be relatively large. If you don’t have a 1TB hard drive, don’t play games~~~ Why can STL and templates thrive in the gaming industry?

First, they are highly efficient, and I won’t elaborate further. Secondly, the repetitiveness of games is too high. Recall that DOTA, League of Legends, and Honor of Kings have very similar gameplay, right? It is precisely because of this high similarity that code reuse becomes very necessary; otherwise, the efficiency of industrializing games would be very low. The reason why large-scale games can be released in half a year is due to STL and templates. Do you believe it? I say it is thanks to game engines. Do you believe it? I say game engines and STL/templates are intertwined; do you believe it?

In summary, the programming philosophy of C++ is very helpful for embedded developers, with the direct effect of significantly reducing your code size and logical complexity. However, the principles of STL and templates are not suitable for most embedded environments because the special nature of embedded software often exceeds generality, and the demand for code reuse is not strong. But as long as you understand why they were created, you will choose the appropriate environment for their use.

You might also like:

Embedded Software: Functional vs Non-Functional Programming

Embedded Field: The Ultimate Showdown Between Linux and RTOS!

Embedded Performance Metrics Hide These Secrets, How Many Do You Know?

Embedded Software Advanced Guide, Let’s Level Up Together!

Embedded Device Networking: From Basics to Practice!

Embedded Programming Models | MVC Model

Embedded Programming Models | Observer Pattern

Step-by-Step Guide to Building an Embedded Containerized Development Environment!

An Elegant Multi-Functional Debugger for Embedded Systems!

A Very Lightweight Embedded Logging Library!

A Very Lightweight Embedded Thread Pool Library!

Popular C Language Projects on GitHub!

Practical | Teach You to Control Lights via Web in 10 Minutes

Essential Skills for Embedded Development | Git Submodules

Leave a Comment