Demystifying C++
In the world of programming, there is a constant evolution and adaptation of languages and tools to meet the ever-growing demands of software development. While C++ is considered one of the most powerful and versatile programming languages, its complexity can often be intimidating and challenging. In this article series, we take a look behind the scenes and demystify the sometimes complex C++ constructs through the lens of a C++ to C transpiler. Whether you are an experienced developer or someone just delving into the depths of C++, the articles offer fascinating insights into the machinery that drives this powerful language.
C++ to C Transpiler
A transpiler, also known as a source-to-source compiler, is a special tool that translates the source code of one programming language into the source code of another programming language. Unlike traditional compilers that translate source code into machine code, transpilers convert code from one high-level language to another.
At emmtrix, we have developed an C++ to C transpiler. It is based on the clang, a state-of-the-art compiler frontend that is part of the broader LLVM project. A standout feature of our transpiler is ensuring semantic equivalence between the original C++ code and the generated C code. This means that despite the differences between the two languages, the translated code exhibits the same behavior as the original code.
To ensure semantic equivalence, a comparison tool is used. This tool translates both the original C++ code and the generated C code into the LLVM IR (Intermediate Representation) and compares these two representations. Through this comparison, it can be ensured that the generated code not only produces the same output in test cases but also that semantically identical code is produced on every run (or an error is displayed). This approach is recognized as a method for ensuring error-free operation in both ISO26262 and DO-178C.
The transpiler supports all C++14 language features as well as common GCC/Clang language extensions. Only exceptions are not fully supported because they cannot be replicated in C on a 1-to-1 basis. In addition to the C++ standard, the Itanium C++ ABI [1] is used, which specifies the binary interface (i.e., application binary interface, ABI), for example, how classes with inheritance are implemented.
Within the article series, the transpiler is used to demystify C++. The C output makes the implementation of the C++ constructs by the compiler easily understandable.
Using the Transpiler to Demystify C++
During the development of the transpiler, we found that it can be used to demystify C++ constructs. By examining the generated C code, we can gain insights into how the C++ constructs are implemented by the compiler. This can be particularly helpful for developers who are new to C++ or for those who want to understand the inner workings of the language.
This finding led us to create a series of articles that explore various C++ constructs and how they would be implemented in C. With the help of the transpiler, we can see how the C++ constructs are translated into C code, shedding light on the underlying mechanisms of the language.
In the following articles, we compare C++ constructs with their equivalent C code. Please note that the provided C code examples are simplified for better readability and understanding. Compared to the original code generated by the transpiler, the C code examples are
- simplified
- incomplete
- don't use name mangling
- may contain readable names that are syntactically incorrect in C
- avoid attributes like static, inline, __attribute__((weak)), __attribute__((section("name"))), __attribute__((aligned(8))), etc.
C++ Construct
- Name Mangling
- Classes
- Virtual classes (polymorphism)
- New and delete operators
- Initialization of global variables
- Templates
- Cleanup code
- Range-based for loops
- Strict return
Ideas for Future
- Member function pointers
- Array new and delete
- Exceptions
- Direct call to `operator =` vs. `=` operator and parameter evaluation order