FreeRTOS相关:宏定义函数与普通函数的区别

本文探讨了FreeRTOS中宏定义函数与普通函数的区别,包括编译与执行过程的不同,以及在代码量、执行效率上的差异。通过实验验证,宏定义函数在执行效率上优于普通函数,但在代码重复性和安全性方面存在不足。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FreeRTOS相关:宏定义函数与普通函数的区别

相关博客FreeRTOS解析:List

FreeRTOS的list.h(其它文件中也有)中定义了大量的宏定义函数。单单从形式看宏定义的函数和普通函数并无太大的区别,但事实上两者还是有很大不同。

  • 宏定义函数与普通函数在编译过程上不同。 在编译时,对于宏定义函数而言,预编译时会将这些宏定义函数按展开的规则直接展开成语句,并且宏定义函数在代码中书写多少次,便展开多少次,拷贝相应的代码插入,生成相应的指令,而对于普通函数而言其只会生成一份相应的指令,调用处会生成传参指令和调用指令实现对函数的调用。

  • 宏定义函数与普通函数在执行过程上不同。 在实际执行过程中,宏定义式函数所有的语句都是普通语句执行,而普通函数由于需要调用的缘故,需要进行开辟栈空间、压栈、出栈等操作。

基于以上两点不同使得宏函数和普通函数在使用和设计上有很大差异。

由于编译时,宏函数是按照宏定义展开规则进行展开的,这一点在提高它的灵活性的同时也会带来许多问题。例如它可以是一些函数的使用变得更为简单

#define DEF_MALLOC(n, type)  ( (type *) malloc((n)* sizeof(type)))
    int *ptr;
    ptr = (int *) malloc( (5) * sizeof(int) );
    ptr = DEF_MALLOC( 5, int );

显然宏定函数在书写上要比普通函数简洁美观的多。但宏展开的一大弊端是它不会对参数类型进行检查,也不符合函数调用的一些规则,而且在定义时要格外小心其展开的结果是否是我们想要的结果,往往需要加上{}或()加以限制,例如以下的代码

#define MAX(x, y)  ((x)>(y)?(x):(y))
    int x = 1;
    int y = 3
    MAX(++x,--y);

以上代码的本意可能是比较++x和–y谁更大,但实际情况却是

((++x)>(--y)?(++x):(--y))

违背了代码原本想要表达的含义。同时宏定义函数实际上被多次展开这一特点使得其在相同代码量和相同插入次数下,编译出的代码量要比普通函数多得多。例如

// 若函数fun()和DEF_FUN()代码完全一样则,以下普通函数代码编译结果为100byte
    fun();
    fun();
    fun();
    fun();
    // 那么以下宏定义函数编译结果可能要接近400byte,是普通函数的4倍
    DEF_FUN();
    DEF_FUN();
    DEF_FUN();
    DEF_FUN();

在执行过程中由于出入栈等操作开销,相同的普通函数要比宏定义函数的执行效率低,使用以下代码在PC机上进行实验验证

#include "stdio.h"
    #include "time.h"

    #define DEF_MAX(x,y) ((x)>(y)?(x):(y))

    int max(int x,int y)
    {
        return ((x)>(y)?(x):(y));
    }

    int main(void)
    {
        unsigned long long int i = 0;
        unsigned long long int times = 100;
        int x = 1;
        int y = 2;
        clock_t start, finish; 

        start = clock(); 
        for(i=0;i<times;i++)
        {
            max(x, y);
        }
        finish = clock(); 
        printf("common fun time %d\r\n",finish - start);

        start = clock(); 
        for(i=0;i<times;i++)
        {
            DEF_MAX(x, y);
        }
        finish = clock(); 
        printf("macro fun time %d\r\n",finish - start);

        return 0;
    }

实验结果如下

次数10100100010000100000
普通函数耗时1014564824808
宏定义函数耗时58221781672

从实验结果看,宏定义函数效率的确高于普通函数。

在实际应用中到底使用宏定义函数还是普通函数需要根据实际需求而定,个人认为当出现小段代码需要多次调用时可以使用宏函数来提高效率,宏函数应该保持短小简洁。

为结合普通函数定义更加安全,而宏函数较为高效的优点,有些编译器提供inline关键字,可以用来声明内连函数。

inline void fun()
    {
        \\ 一些代码
    }

inline函数和宏函数一样,它会在代码书写处直接拷贝一份指令,不会像普通函数一样单独生成指令然后调用,这使得其相对普通函数而言其仍然是高效的。但与宏函数不同,它是在编译阶段展开到生成指令中的,而不是预编译阶段展开到代码中,它会进行参数类型的检查,符合函数的一般直觉。另外,在实际运行过程中inline函数是可以使用调试器调试的,而宏函数不行。并不是所有函数都适合作为内联函数,内联函数应该满足以下要求,否则编译器可能会忽略inline关键字将其作为普通函数处理。

  • 不使用循环(for,while)。

  • 不使用switch。

  • 不能进行递归调用。

  • 代码应短小,不能过长。

### FreeRTOS 的优点、特点优势 #### 小巧高效 FreeRTOS 是一种非常小巧的操作系统内核,特别适合用于资源受限的嵌入式设备。其核心代码量较少,在某些配置下甚至可以减少到仅几千字节的程度[^1]。 #### 实时性能强 作为一款实时操作系统(RTOS),FreeRTOS 提供了强大的实时调度能力。它能够确保高优先级的任务得到及时响应并执行,即使是在多任务环境下也能保持良好的实时性表现[^4]。 #### 支持多种平台 尽管最初设计是为了适应微控制器环境,但事实上 FreeRTOS 并不局限于此。它可以运行于各种不同类型的硬件平台上,并且支持广泛的处理器架构。 #### API 设计友好 为了方便开发者调用,FreeRTOS 提供了一组易于理解和使用的应用程序接口(API)。值得注意的是,针对不同的应用场景(如普通任务上下文中或中断服务程序(ISR)),提供了相应的API版本来满足特定需求;对于后者而言,这些函数名称通常带有`FromISR`后缀以便区分[^3]。 #### 命名规范严格 在开发过程中遵循严格的命名规则有助于提高代码可读性和维护效率。FreeRTOS 对变量、函数以及宏定义都制定了清晰明确的名字约定标准,这使得学习者更容易理解各个组件的功能作用[^2]。 #### 数据类型统一 采用标准化的数据类型声明方式不仅增强了跨平台兼容性,同时也减少了因编译器差异而导致的问题发生概率。通过这种方式,无论目标平台如何变化,都能保证一致性的编程体验。 ```c // 示例:创建一个简单的任务 void vTaskCode(void *pvParameters){ while (true){ // Task code here... vTaskDelay(pdMS_TO_TICKS(100)); // Delay for 100ms } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值