几十年来,嵌入式软件工程师们一直在争论是否应该使用C++替代C语言进行开发工作。56%的嵌入式软件是用C语言编写的。然而,C++已经逐渐普及,大约23%的新嵌入式软件项目都是用C++编写的。那么,嵌入式开发人员要如何将嵌入式代码库从C转换为C++?
这种过渡最好分四个阶段进行:
1.编译器应该将源代码解释为C++而不是C。
对于某些编译器,将源文件从“.c”重命名为“.cpp”就足够了;其他命令行需要特定的参数。由于C几乎是C++的子集,所以这一步骤通常不需要对源代码进行任何更改。但也有例外。重要的是,首先对整个代码库执行该步骤,否则可能无法对某些模块执行以下步骤,例如,如果其他模块使用这些模块,此步骤还可能导致“损坏”,即对生成的链接器符号的名称进行破坏。对于链接“.c”和“.cpp”模块,需要外部“c”。可以通过同时对所有模块执行此步骤来避免这种情况。
2.修改代码以使用简单的C++语言特性。
为了从更好的语法和更高的类型安全性中获益,现在嵌入式开发人员可以通过以下方式改进以前的C代码:
l 使用名称空间而不是前缀变量/函数名称;
l 使用作用域枚举而不是常规C枚举;
l 使用C++bool代替专门定义的C bool;
l 使用static_assert而不是运行时断言(如果可能);
l 使用constexpr而不是常量宏,并且(如果可能)使用const
l 使用模板函数而不是“函数”宏。
3.将可识别的模拟“C-OOP代码”转换为真实的OOP代码。
例如,有一个名为INSTANCE_T的结构,指向该结构的指针被传递给编辑它的各种函数。将结构转换为适当的类,并将函数转换为类组件。不要忘记正确指定public/private。如果有init函数,嵌入式开发人员请记住将其转换为类的构造函数。
在前三个步骤中,源代码变得更加可读、可维护和类型安全。根据我们的经验,在大多数情况下,可执行代码的大小不会改变。我们甚至可以在ROM中的大多数模块上执行步骤1和2,因为在可执行代码中,没有一个字节通过重新编译而改变。
4.引入更复杂的OOP方法和其他C++语言特性。
你应该小心地迈出最后一步。例如,开发团队应该收到关于应该使用哪些C++语言特性以及如何使用的指南。例如,类成员函数不应被不必要地定义为虚拟,也不应使用STL。
新模块现在将从一开始就按照这些指南进行编程。然而,将这一步骤应用于整个现有代码库需要大量的工作。一个好的策略是嵌入式开发人员有选择地为每个模块执行最后一步,例如,如果模块无论如何都要进行重构。随着时间的推移,代码库从C变为更复杂的C++代码。我们的代码库已经过渡了大约三年。在此期间,已有数十种产品从这个代码库中脱颖而出。一些较旧且非常稳定的模块(例如设备驱动程序)仍在C语言中,并将保持更长时间。我们从未觉得这种混合是同一代码库中的问题。
结论:使用C语言,代码更安全、更可维护++
有一个强大的C++子集适合于实现深度嵌入式系统。这允许程序员编写更安全、更可维护的代码,并实现在C语言中不可能实现的优化。通过在上述子集内移动,可以避免可执行代码中不必要的开销。嵌入式开发人员使用四阶段方法,可以将现有的生产代码库从C灵活地转换为C++。