【问题标题】:One level macro expansion in CC中的一级宏扩展
【发布时间】:2020-03-27 16:58:12
【问题描述】:

我在一个库中工作,该库是其他库的接口,其中包含几个已定义的宏,例如:

#define GPIOx  some stuff
#define __HAL_RCC_GPIOx_CLK_ENABLE() some other stuff

其中 x 是一个字母 (A,B,C,...)。

我无法更改这些宏(或者我不应该更改它们,因为它们被其他组件使用)。

在我正在工作的库中,我正在尝试定义一些其他用户可以修改的宏,例如:

#define DHT_GPIO_Port  GPIOx

我想定义一个宏,它使用这样的定义来生成另一个宏名称:

#define __HAL_DHT_CLK_ENABLE(DHT_GPIO_Port)  __HAL_RCC_## DHT_GPIO_Port ##_CLK_ENABLE()

这是因为我想为我的库使用宏而不是 __HAL_RCC_GPIOx_CLK_ENABLE(),因为它会根据用户定义的 GPIO 而有所不同。

但是,当我尝试使用我的 __HAL_DHT_CLK_ENABLE(DHT_GPIO_Port) 宏时,它会扩展为 __HAL_RCC_DHT_GPIO_Port_CLK_ENABLE(),而不是 __HAL_RCC_GPIOx_CLK_ENABLE()。

另一方面,我尝试将它放在另一个宏中,但它也扩展了 GPIOx,而我不需要。

也许这是一个初学者的问题,但你能帮助在其他宏连接中仅扩展宏 DHT_GPIO_Port 的第一级吗?

【问题讨论】:

    标签: c macros expansion


    【解决方案1】:

    这没有太多意义。使用内联函数代替无用的难以阅读的宏

    #define SINLINE static inline __attribute__((always_inline))
    
    SINLINE void  __HAL_DHT_CLK_ENABLE(GPIO_TypeDef * const gpio)
    {
        switch((uint32_t)gpio)
        {
            case (uint32_t)GPIOA:
                __HAL_RCC_GPIOA_CLK_ENABLE();
                break;
            case (uint32_t)GPIOB:
                __HAL_RCC_GPIOA_CLK_ENABLE();
                break;
            case (uint32_t)GPIOC:
                __HAL_RCC_GPIOA_CLK_ENABLE();
                break;
        }
    }
    

    当您启用优化并使用常量表达式调用它时(如 GPIOA.GPIOBswitch ... case 将被优化。您还可以使用非常量参数调用它 - 这是您无法使用的宏。

    避免使用诸如牌匾之类的宏。

    【讨论】:

    • 感谢您的反馈!事实上,我曾尝试探索其他替代方案,例如使用函数,但我无法获得正确的 switch ... case 条件。你的提议很棒。我认为它可以通过宏来解决,但正如你评论的那样,我也在其他 cmets 中阅读过,函数会更好地解决它。再次感谢!
    【解决方案2】:

    以下应该有效:

    #define __HAL_DHT_CLK_ENABLE_(DHT_GPIO_Port)  __HAL_RCC_## DHT_GPIO_Port ##_CLK_ENABLE()
    

    定义 __HAL_DHT_CLK_ENABLE(DHT_GPIO_Port) __HAL_DHT_CLK_ENABLE_(DHT_GPIO_Port)

    例如下面一行:

    __HAL_DHT_CLK_ENABLE(GpioA)
    

    产生:

    __HAL_RCC_GpioA_CLK_ENABLE()
    

    【讨论】:

    • 感谢您的回答,但我担心这个想法是用 GpioA 的内容代替,而不仅仅是 GpioA,例如在我的情况下 DHT_GPIO_conf 是 GPIOA 所以当在宏中替换时应该检索 __HAL_RCC_GPIOA_CLK_ENABLE() 时要求 __HAL_DHT_CLK_ENABLE_(DHT_GPIO_Port)。不要忘记 GPIOA 也是一个宏,所以不应该在那里扩展。
    • 你不能阻止宏被扩展,你能做的最好的就是#undef你不想扩展的宏,但我不知道gcc或clang是否支持# pragma push_macro/#pragma pop_macro(就像 MSVC 一样),或者如果他们有任何替代方法来做同样的事情。
    • 感谢您的澄清。显然,它无法使用宏来解决。
    猜你喜欢
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    • 2014-02-14
    • 2023-03-07
    • 1970-01-01
    • 2021-09-14
    • 2015-01-27
    • 2010-11-02
    相关资源
    最近更新 更多