嵌入式C语言之结构体封装函数

说明:

在嵌入式系统中,结构体封装函数可以用于对于嵌入式硬件资源进行抽象和封装,从而提高软件的可维护性和可移植性。结构体封装函数通常包含数据和行为,并提供了对数据的访问和操作方法。

比如可以将硬件驱动函数封装在结构体中,方便对外提供统一的API接口,同时也便于代码的移植和扩展。另外,结构体封装函数还可以用于实现状态机、任务调度等复杂的系统功能。

在C语言中,结构体不仅可以封装数据,还可以封装函数指针。这种方式可以用于实现回调函数、状态机等,提高代码的复用性和可维护性。特别是在嵌入式当中,应用是非常多的。

结构体封装函数的作用:

  1. 将函数指针和参数打包成一个结构体,实现了代码的模块化和可复用性。

  2. 在结构体中可以定义多个函数指针,实现了对函数的分类管理和调用。

  3. 结构体可以作为函数的参数或返回值,传递和返回函数指针和参数。

结构体封装函数的应用:

 

  • 回调函数:将函数指针和参数打包成一个结构体,传递给API函数,在API函数内部执行该函数。

  • 状态机:将每个状态对应的处理函数封装成一个结构体,根据当前状态调用相应的处理函数。

  • 事件驱动:将事件处理函数封装成一个结构体,通过事件触发调用相应的处理函数。

  • 线程池:将任务处理函数封装成一个结构体,加入任务队列后由线程池调用执行

结构体封装函数的好处:

  • 更好的隐藏实现细节:结构体封装函数使得函数的实现细节被封装在结构体内部,只有结构体暴露给外部的函数指针,实现了良好的封装和信息隐藏。

  • 更加灵活的函数调用:函数指针可以被动态修改,从而实现动态的函数调用。例如,在状态机中,根据不同的状态,可以将相应的处理函数指针赋值给一个函数指针变量,从而实现状态的转换和函数的调用。

  • 更加方便的扩展性:结构体封装函数可以轻松地添加新的函数指针,从而扩展功能。在需要添加新功能时,只需要定义一个新的函数指针,并添加到结构体中,就可以实现功能的扩展,而不需要修改原有的代码。

  • 更加通用的代码:结构体封装函数可以使用于各种不同的编程范式,例如面向对象编程(OOP)和函数式编程(FP),从而实现通用的代码。例如,在OOP中,结构体可以被看作是一个对象,函数指针可以被看作是对象的方法,从而实现OOP编程的思想。

  • 更加易于维护:结构体封装函数使得代码更加清晰、易于维护和修改。由于函数指针的定义和使用都在结构体内部,因此修改或调整代码时,只需要修改结构体中的函数指针定义或调用方式,而不需要修改其他部分的代码,从而使得代码更加健壮、易于维护和修改

  • 模块化:通过结构体封装函数,可以将多个函数和数据结构组合成一个模块,以便于模块化设计和维护。这种方法可以将代码的复杂性分解到不同的模块中,降低了代码的耦合性,提高了代码的可读性和可维护性。

  • 代码复用:结构体封装的函数可以通过传递结构体的方式重用同一个函数。这种方式可以大大减少代码量,提高代码的复用性和可维护性。

  • 可扩展性:当需要增加新的功能时,只需增加新的函数和数据结构,而不需要修改现有代码。这种方式可以大大减少代码的修改和调试时间,提高代码的可扩展性和可维护性。

  • 保护数据:通过结构体封装函数,可以将数据和函数封装在一个结构体中,防止外部代码对数据的非法访问和修改。

  • 提高安全性:将函数和数据封装在一个结构体中,可以防止其他函数对数据的非法操作,从而提高程序的安全性。

  • 举例1

    1

     1/* 定义封装函数结构体由外部调用*/
     2typedef struct {
     3    int x;
     4    int y;
     5    void (*move_up)(int steps);
     6    void (*move_down)(int steps);
     7    void (*move_left)(int steps);
     8    void (*move_right)(int steps);
     9} Point;
    10
    11// 定义结构体中的函数
    12void move_up(int steps) {
    13    // 向上移动steps个单位
    14    // ...
    15}
    16
    17void move_down(int steps) {
    18    // 向下移动steps个单位
    19    // ...
    20}
    21
    22void move_left(int steps) {
    23    // 向左移动steps个单位
    24    // ...
    25}
    26
    27void move_right(int steps) {
    28    // 向右移动steps个单位
    29    // ...
    30}
    31
    32int main() {
    33    // 初始化结构体
    34    Point point = {
    35        .x = 0,
    36        .y = 0,
    37        .move_up = move_up,
    38        .move_down = move_down,
    39        .move_left = move_left,
    40        .move_right = move_right
    41    };
    42
    43    // 调用结构体中的函数
    44    point.move_up(10);
    45    point.move_right(5);
    46
    47    return 0;
    48}
    

    在上面的示例代码中,我们定义了一个结构体Point,其中包含了两个整型变量xy,以及四个函数指针move_upmove_downmove_leftmove_right。每个函数指针指向一个移动函数,用于在平面坐标系中移动点的位置。通过使用结构体封装函数,我们可以将函数和数据封装在一起,方便地进行操作和管理。

    main()函数中,我们首先通过初始化的方式,将结构体中的成员变量和函数指针初始化。然后,我们使用结构体中的函数指针,调用了move_up()move_right()函数,分别将点向上移动10个单位和向右移动5个单位。

    值得注意的是,在实际应用中,我们需要根据实际情况修改函数的实现,以及结构体中的成员变量和函数指针的数量和类型。同时避免滥用。

    举例2

     1typedef struct {
     2    void (*init)(void);
     3    void (*write)(uint8_t data);
     4    uint8_t (*read)(void);
     5} spi_t;
     6
     7void spi_init(void) {
     8    /* SPI初始化代码 */
     9}
    10
    11void spi_write(uint8_t data) {
    12    /* SPI写入数据 */
    13}
    14
    15uint8_t spi_read(void) {
    16    /* SPI读取数据 */
    17}
    18
    19int main(void) {
    20    spi_t spi = {spi_init, spi_write, spi_read};
    21
    22    spi.init();
    23    spi.write(0xAA);
    24    uint8_t data = spi.read();
    25
    26    return 0;
    27}
    

    在举例2这个例子中,我们定义了一个spi_t类型的结构体,它包含了三个成员函数指针,分别对应SPI总线的初始化、写入和读取操作。在main函数中,我们定义了一个spi结构体变量,并且初始化它的函数指针成员。接下来,我们通过spi结构体变量的函数指针成员,分别调用了SPI总线的初始化、写入和读取操作。

    使用结构体封装函数可以使代码更加清晰明了,减少了代码的冗余和重复,同时也方便代码的扩展和维护。

    举例3

    假设我们需要控制一个LED灯的亮度,可以使用PWM(脉冲宽度调制)技术来实现。为了方便控制,我们可以使用一个结构体来封装控制LED灯的函数和变量。

     1typedef struct {
     2    uint8_t duty_cycle;     // 占空比
     3    void (*set_duty_cycle)(uint8_t duty_cycle);  // 设置占空比的函数指针
     4    void (*start)(void);    // 启动PWM输出的函数指针
     5    void (*stop)(void);     // 停止PWM输出的函数指针
     6} pwm_control_t;
     7
     8// 设置占空比
     9void set_duty_cycle(uint8_t duty_cycle) {
    10    // 设置占空比的代码
    11}
    12
    13// 启动PWM输出
    14void start_pwm(void) {
    15    // 启动PWM输出的代码
    16}
    17
    18// 停止PWM输出
    19void stop_pwm(void) {
    20    // 停止PWM输出的代码
    21}
    22
    23int main(void) {
    24    pwm_control_t pwm;
    25
    26    pwm.duty_cycle = 50;   // 设置占空比为50%
    27    pwm.set_duty_cycle = set_duty_cycle;
    28    pwm.start = start_pwm;
    29    pwm.stop = stop_pwm;
    30
    31    pwm.set_duty_cycle(pwm.duty_cycle);  // 设置占空比
    32    pwm.start();  // 启动PWM输出
    33
    34    while (1) {
    35        // 循环执行其他任务
    36    }
    37}
    

    在上面的代码中,我们定义了一个名为pwm_control_t的结构体,其中包含了一个占空比成员变量duty_cycle和三个函数指针set_duty_cyclestartstopset_duty_cycle函数用于设置占空比,start函数用于启动PWM输出,stop函数用于停止PWM输出。

    main函数中,我们创建了一个pwm_control_t类型的结构体变量pwm,并分别给结构体的成员变量和函数指针赋值。接着,我们调用了set_duty_cyclestart函数来设置占空比和启动PWM输出。

    结构体封装函数的好处在于,我们可以通过创建不同的结构体变量来控制多个LED灯,而且不同的LED灯可以使用不同的PWM参数。此外,如果需要修改PWM输出的实现方式,只需要修改startstop函数即可,而不需要修改每个LED灯。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux下使用C语言封装SQLite可以通过SQLite提供的C API来实现。SQLite是一个轻量级、嵌入式的数据库引擎,适用于移动设备和单用户应用程序。下面是使用C语言封装SQLite的基本步骤: 1. 安装SQLite库:在Linux上安装SQLite库可以通过包管理器(如apt、yum)进行安装,或者从SQLite官方网站下载源代码进行编译安装。 2. 包含SQLite头文件:在C语言代码中包含SQLite的头文件,例如:`#include <sqlite3.h>` 3. 打开数据库连接:使用`sqlite3_open()`函数打开与数据库的连接,并获取一个`sqlite3`结构体的指针。示例代码如下: ```c sqlite3 *db; int rc = sqlite3_open("database.db", &db); if (rc != SQLITE_OK) { // 处理连接失败的情况 } ``` 4. 执行SQL语句:可以使用`sqlite3_exec()`函数执行SQL语句,该函数可以处理任意类型的SQL语句,包括查询、插入、更新和删除等。示例代码如下: ```c const char* sql = "CREATE TABLE IF NOT EXISTS students (id INTEGER PRIMARY KEY, name TEXT, age INT)"; rc = sqlite3_exec(db, sql, 0, 0, 0); if (rc != SQLITE_OK) { // 处理SQL语句执行失败的情况 } ``` 5. 处理查询结果:可以使用`sqlite3_exec()`函数的第三个参数来指定一个回调函数,在查询时调用该函数处理查询结果。示例代码如下: ```c int callback(void* data, int argc, char** argv, char** column_names) { for (int i = 0; i < argc; ++i) { printf("%s = %s\n", column_names[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0; } const char* sql = "SELECT * FROM students"; rc = sqlite3_exec(db, sql, callback, 0, 0); if (rc != SQLITE_OK) { // 处理SQL语句执行失败的情况 } ``` 6. 关闭数据库连接:使用`sqlite3_close()`函数关闭与数据库的连接。示例代码如下: ```c sqlite3_close(db); ``` 通过上述步骤,可以在Linux下使用C语言封装SQLite,实现对数据库的增删改查等操作。当然,这只是SQLite的基本使用方法,还有更多高级的特性和操作可以进一步探索。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BinaryStarXin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值