rt_hw_console_output为什么写在那个函数里都可以被调用

发布于 2020-10-21 15:35:41

要实现rt_kprintf就必须实现rt_hw_console_output函数,
为什么rt_hw_console_output在哪个.c里面实现,系统都是找到的,我也没有头文件引用。这是用到了什么技术做到的。

查看更多

关注者
0
被浏览
587
wenbodong
wenbodong 2020-10-21

在kservice.c中,有如下代码:

RT_WEAK void rt_hw_console_output(const char *str)
{
    /* empty console output */
}
RTM_EXPORT(rt_hw_console_output);

/**
 * This function will put string to the console.
 *
 * @param str the string output to the console.
 */
void rt_kputs(const char *str)
{
    if (!str) return;

#ifdef RT_USING_DEVICE
    if (_console_device == RT_NULL)
    {
        rt_hw_console_output(str);
    }
    else
    {
        rt_uint16_t old_flag = _console_device->open_flag;

        _console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
        rt_device_write(_console_device, 0, str, rt_strlen(str));
        _console_device->open_flag = old_flag;
    }
#else
    rt_hw_console_output(str);
#endif
}

定义了rt_hw_console_output函数,与一般函数不同之处在于多了个RT_WEAK,这个宏定义在rtdef.h中,gcc环境下对应的是:

#define RT_WEAK                     __attribute__((weak))

具有这种属性的函数,可以在其他地方重写,比如用户代码中。如果用户重写了,那么最终链接的是用户的函数;否则,链接的是kservice.c中的这个。

总结一下,weak属性为设计底层库时提供了一种便利:可定义一些可被用户重写的函数,并且无论用户是否重写,代码都能顺利编译。其实这种技术,在stm32的HAL库中被大量使用,比如:

/**
  * @brief  Initializes the MSP.
  * @retval None
  */
__weak void HAL_MspInit(void)
{
  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_MspInit could be implemented in the user file
   */
}

对了,题主说自己没提供头文件,问rtthread是如何引用的。这说明题主可能没有完全掌握头文件引用的方法。就算你提供一个头文件,那rtthread又怎么知道你的头文件的路径是啥呢,又怎么能#include的呢。如果rtthread指定一个需要用户实现的函数,在不用weak的情况下,可以这么做:

extern void rt_hw_console_output(const char *str);

/**
 * This function will put string to the console.
 *
 * @param str the string output to the console.
 */
void rt_kputs(const char *str)
{
    if (!str) return;

#ifdef RT_USING_DEVICE
    if (_console_device == RT_NULL)
    {
        rt_hw_console_output(str);
    }
    else
    {
        rt_uint16_t old_flag = _console_device->open_flag;

        _console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
        rt_device_write(_console_device, 0, str, rt_strlen(str));
        _console_device->open_flag = old_flag;
    }
#else
    rt_hw_console_output(str);
#endif
}

它不需要引用你的头文件,既然函数接口是它规定的,那它自己声明一下就行了。当然,相比于weak,这种实现要求用户必须定义rt_hw_console_output函数,否则无法编译。

2 个回答
Remember
Remember 2020-10-21

rthw.h里就有啊

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览