How to Rewrite C++ Programs in C?

Due to the C++ interpreter occupying approximately 500k more storage space than the C language interpreter, it is necessary to rewrite source programs written in C++ into C to save limited storage space, reduce costs, and improve efficiency.

The biggest difference between C++ and C is the concept and features of classes in C++. The problem of converting C++ to C becomes a question of how to eliminate class-based structures.There are two methods: The first method is to remove the object-oriented features from C++, fully understand the logic of the source code, and then rewrite it; the second method is to retain some object-oriented features in C by using structures to implement class functionalities.

The first method is feasible when there are very few classes. However, if there are many classes, fully understanding the source code and rewriting it can be very time-consuming and error-prone. In fact, it may be nearly impossible to fully understand the source code for large projects.

If there are over 140 classes in the program, the second method should be adopted. You can convert one class at a time without much difficulty, and if there are no typographical errors, it is unlikely to make mistakes. Moreover, you may not need to understand the program logic at all; perhaps after the conversion, you will still be unaware of the functionalities the program is supposed to achieve. This is not to say that ignorance is beneficial; rather, it highlights the method’s independence from the program logic itself.

Below, we will discuss some features of C++ and how to implement or replace them in C.Note:

  • Function Ixx is the implementation of the constructor for class xx.
  • The member functions of the original class are prefixed with the structure name + ‘_’ as their function names.
  • Function pointer U is the declaration of the destructor for the original class.
  • U + structure name is the implementation of the destructor for the original class.
  • Fun-_ + structure name is used to point to the member function pointer of that structure.
  • Subsequent occurrences of the above situations will not be explained again.

Member Functions and Data Members of Classes

Since struct does not control access to its members, additional mechanisms must be added for access control, which complicates the program. Therefore, access control must be abandoned.

1) Data members of classes can be directly converted to data members of structures in C.2) Functions need to be converted to corresponding function pointers, as struct does not allow function declarations and definitions. If a function has modifiers like virtual or inline, they must also be removed. For example, the function void funca(int a); becomes void (*funca)(struct B *p, int a);. You can see that the function pointer prototype includes a pointer to struct B, which is necessary to operate on the class’s members within the function. In member functions of classes, there is implicitly a pointer to itself, known as the this pointer, in the parameter list.3) Static members must be defined as global variables or global functions, as structures cannot have static members.

Constructors of Classes

When a class is instantiated, the default constructor of the class is called. In struct, a function pointer with the same name must be defined to point to an initialization function that has constructor functionality. Unlike constructors, the initialization function must include statements to initialize the function pointer. When using it, malloc must be used to create structure variables instead of new, and the initialization function must be called manually.

As shown in the following example:

class A{public:    A();    ~A();void func(int a);private:int b;};A::A(){    b=0;}void A::func(int a){    b=a;}typedef struct classA A;struct classA{void (*A)(struct classA *p);// Constructor function pointervoid (*U)(struct classA *p);// Destructor function pointervoid (*func)(struct classA *p,int a);int b;};void fun_A(A *p){     p->func=classA_func; // Initialize function pointer}void IA(A *p) // Constructor, naming convention is to prefix with I{     fun_A(p);     p->b=0;    // Original constructor functionality}void classA_func(A *p,int a){    p->b=a;}

In usage, it is done as follows:

  A *s=(A*)malloc(sizeof(A));    s->A=IA;    s->A(s);

Destructors of ClassesThe destructor of a class is responsible for releasing the resources it occupies.In C, any struct uses function pointer U to replace the destructor. The reason all structs use pointer U is based on the following situation:If a subclass pointer is assigned to a base class pointer, the base class pointer does not need to consider which destructor function name to call when releasing; it only needs to call member function U. Member function U must be specified in the fun_class_name() function like a regular member function.The destructor of a class is called by the system, while in C, it must be called explicitly. The timing of the call must be accurately determined.Copy Constructors of ClassesThe primary purpose of a class’s copy constructor is to speed up the construction of classes in the following situations:1. When passed as a parameter to a function. (additem(Itema))2. When returned as a function value.3. When instantiated as a parameter. In these three cases, the system directly calls the class’s copy constructor instead of the constructor. Note: C=D; will not call the copy constructor; in this case, the overloaded ‘=’ operator method is used. (See operator overloading) Since struct variables in C are defined using pointers, copy constructors will not be used, so they are not considered. For original function parameters or return values that require class variables, they must all be converted to class pointers. The situation of instantiating a class as a parameter can be resolved by defining another constructor with parameters.

Inline Functions and Virtual Functions of Classes

The modifiers inline and virtual must be removed from inline functions and virtual functions. The body of inline functions must be removed, and the inline function should be defined as a regular function outside. As follows:

How to Rewrite C++ Programs in C?

Change to:

typedef classB B;struct classB{    …void (*funb)(struct classB *p);int (*add)(struct classB *p);int a;int b;}void classB_funb(B *p){     …}int classB_add(B *p){return p->a+p->b;}void fun_classB(B *p){     …     p->funb=classB_funb;     p->add= classB_add;}

Overloading

In classes, overloading includes function overloading and operator overloading: 1) Function Overloading The conditions for function overloading are: the function names are the same, but the number of parameters or the types of parameters are different.Thus, when calling, different functions will be invoked based on the different input parameters.In C, different names must be used instead, as there is no other solution. 2) Operator Overloading Operator overloading is only to satisfy the general usage habits of operators without causing errors.C does not support operator overloading, but a function can be defined to achieve this functionality.This is the general modification for classes.

Inheritance of Classes

1) Single Inheritance If there is an inheritance relationship between classes, first modify the base class according to the general method, and then copy the definition part of the base class to the front of the subclass. Besides changing the base class constructor name to the subclass constructor name, no other modifications should be made to the base class definition. In the constructor, the base class constructor must be called, and if the subclass overrides a function of the base class, the function pointer must be redirected to the subclass function. This is to maintain the dynamic binding characteristics brought by class inheritance.The inheritance relationship between classes is complex and variable. To ensure the uniqueness of the base class in all subclasses and facilitate modification, the best method is to make the structure part of the base class a macro, which can be directly used in the subclass. 2) Multiple Inheritance Personally, I believe multiple inheritance should be avoided as it can lead to issues such as multiple inheritance paths. Unless it is used for convenience in programming, such as inheriting interfaces, etc. Multiple inheritance can also be modified by copying all members of multiple base classes into the subclass. If there are duplicate member names, prefixes should be added to distinguish them. This refers to cases where there are similarities among base classes; if there are name conflicts between derived classes and base classes, the derived class will override the base class.

Others

The above discusses the main differences and most commonly used features between C++ and C, along with modification methods. There are other features, such as the use of templates, etc., which are designed to facilitate programming and code reuse. C does not have this, so multiple functions must be written to implement them separately. Additionally, the ‘&’ symbol in parameter lists must be replaced with pointers, default values must be removed, and care must be taken to include default values when calling.【Paid】 STM32 Embedded Resource Package

Leave a Comment