03-在ESP-IDF中使用C++面向对象编程
ESP-IDF同样提供了关于C++使用的例程,可以在你电脑中的ESP-IDF安装路径下找到关于ESP-IDF C++的更多内容可以阅读下下方的官方文档ESP-IDF C++支持。
在ESP-IDF中使用C和C++进行混合编译
ESP-IDF是Espressif Systems开发的官方IoT开发框架,用于编程和开发ESP32系列的微控制器。虽然ESP-IDF主要使用C语言编写,但它也支持使用C++进行开发
为什么要进行混合编译?
C++是一种功能强大的编程语言,它提供了许多C语言不具备的特性,如类(对象导向编程)、异常处理、函数重载等。然而,C语言在嵌入式系统开发中仍然占据主导地位,因为它更接近硬件,运行效率高,且占用资源少。
因此,混合编译允许开发者在同一个项目中利用C++的高级特性和C的效率。例如,你可以在C++中编写面向对象的代码,用于处理复杂的逻辑和数据结构,同时在C中编写底层的硬件操作代码。
如何进行混合编译?
在ESP-IDF中进行混合编译主要涉及到两个方面:源文件的组织和链接性的处理。
源文件的组织
在ESP-IDF项目中,源文件通常按照组件(component)来组织。每个组件都有自己的目录,包含了该组件的源文件和头文件,以及一个CMakeLists.txt
文件,用于告诉CMake如何编译这些源文件。
在一个混合编译的项目中,你可以有一些组件是用C编写的,一些组件是用C++编写的。例如,你可以有一个用C编写的LED
组件,用于控制LED的亮度和颜色,同时有一个用C++编写的KEY
组件,用于初始化和扫描按键键值。
用一个按键控制LED的项目举例,下面是这个项目的文件构成
main.cpp
,LED.c
,LED.h
,KEY.cpp
,KEY.h
是我们项目中需要编译链接的文件,它们和CMakeLists.txt的文件结构如下
- 02KEY
- components
- LED
- LED.c
- LED.h
- KEY
- KEY.cpp
- KEY.h
- CMakeLists.txt
- main
- main.cpp
- CMakeLists.txt
components组件下的.cpp/,c和.h
components
文件下的CMakeLists.txt
指定了该组件的源文件、头文件目录和依赖项。将 LED/LED.c
和KEY/KEY.cpp
文件作为源文件,LED
和 KEY
目录作为头文件目录,并将 driver
组件作为依赖项(driver
组件是在项目中用到的,所以要将它加入到依赖项)。
idf_component_register(
SRCS "LED/LED.c" "KEY/KEY.cpp"
INCLUDE_DIRS "LED" "KEY"
REQUIRES driver
)
main文件下的main.c
第一步
将main文件夹下的main.c
重命名为main.cpp
第二步
main
文件下的CMakeLists.txt
同样只需要将main.c
改为main.cpp
即可
项目创建自动生成的:
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
修改之后的
idf_component_register(SRCS "main.cpp"
INCLUDE_DIRS ".")
链接性的处理
当C和C++代码在同一个项目中混合使用时,一个重要的问题是链接性(linkage)。链接性决定了一个符号(如函数或变量)在链接时如何被处理。C++支持函数重载,因此在编译后,C++函数的名字会被修饰(mangled)以表示它们的参数类型。然而,C语言没有这个特性,因此C函数的名字在编译后保持不变。
为了解决这个问题,C++提供了extern "C"
这个关键字,用于声明一个符号使用C链接。当C++编译器看到extern "C"
时,它会知道后面的代码应该按照C的规则来处理,因此不会对函数名进行修饰。
在ESP-IDF中,如果你有一个C++组件需要调用C组件的函数,你可以在C++代码中这样声明C函数:
extern "C" void led_set(int date);
同样,如果你有一个C组件需要调用C++组件的函数,需要在C代码中声明C++函数:
extern void led_read(void);
注意,C代码中不需要使用extern "C"
,因为C编译器不支持这个关键字。
下面我们继续拿刚刚按键控制LED的项目举例
以下是main.cpp
,LED.c
,LED.h
,KEY.cpp
,KEY.h
文件的处理方式:
-
main.cpp:在这个文件中,我们了包含
LED.h
和KEY.h
。而void app_main(void)
是ESP-IDF为我们提供的主程序,我们需要使用extern "C"
来声明这个主程序#include "LED.h" #include "KEY.h" extern "C" void app_main(void){ //程序实现----- }
-
LED.c和LED.h:这两个文件应该是C语言编写的,所以我们不需要做任何特殊的处理。
-
KEY.cpp和KEY.h:这两个文件是C++编写的。在
KEY.h
中,我们使用extern "C"
来包含类定义的所有内容。在KEY.cpp
中,需要使用extern "C"
来定义这些成员函数KEY.h
// KEY.h #ifdef __cplusplus extern "C" { #endif class Key { public: // 构造函数 Key(gpio_num_t pin); } #ifdef __cplusplus } #endif
KEY.cpp
// KEY.cpp #include "KEY.h" extern "C" Key::Key(gpio_num_t pin): pin(pin) { // ... }
注意 注意 类的成员函数不要使用inline(内联)要不然.h和.cpp文件可能会无法链接到,我就踩了这个坑😭😭一直以为是CMake写的不对,所以链接不上捣鼓了一天,最后都准备要把ESP-IDF给卸载重装了,在卸载前我还是不信邪,我把程序发给ChatGPT问它有什么问题,好家伙ChatGPT直接点出了问题所在,类的成员函数在类外定义时我用了inline导致的.h和.cpp链接不到,好在解决了,怎么没早点想到让ChatGPT排查错误呢😂😂,学到了,学到了,大家遇到什么问题记得问问AI真的有奇效。
结语
ESP-IDF同样提供了关于C++使用的例程,可以在你电脑中的ESP-IDF安装路径下找到
D:\Espressif\frameworks\esp-idf-v5.2.1\examples\cxx
关于ESP-IDF C++的更多内容可以阅读下下方的官方文档
ESP-IDF C++支持
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)