【问题标题】:Macro constants concatenation using ##使用## 连接宏常量
【发布时间】:2017-07-08 19:36:13
【问题描述】:

我正在为微控制器编写一些库,为此,我使用了类似宏的函数。例如,启用 I2C 模块的类宏函数定义为:

#define I2C_MODULE_ENABLE(_x) \
    I2C##_x##CONLbits.I2CEN = 1

_x 是模块编号(例如,12 在我的例子中)。

如果用户将此类似宏的函数称为I2C_MODULE_ENABLE(1),则预处理器会将其扩展为I2C1CONLbits. I2CEN = 1

但是,如果用户将此类似宏的函数称为 I2C_MODULE_ENABLE(MY_I2C),其中 MY_I2C 是在用户定义的 config.h 文件中定义的宏常量,该文件包含在我的 i2c.h 库中(例如,宏常量定义为#define MY_I2C 1),类宏函数将扩展为I2CMY_I2CCONLbits. I2CEN = 1

我知道我需要在连接之前以某种方式评估 MY_I2C 宏常量,我可以通过添加另一个宏级别来做到这一点:

#define __I2CxCONLbits(_x) I2C##_x##CONLbits
#define I2C_MODULE_ENABLE(_x) \
    __I2CxCONLbits.I2CEN = 1

我的问题是:是否有更优雅的解决方案来解决这个问题,因为我有多个寄存器,例如 CONLbits 寄存器。使用这种方法,我需要为每个寄存器定义一个特殊的 __I2CxREGISTER(_x) 宏。

我试图做这样的事情:

#define __I2Cx(_x) I2C##_x
#define I2C_MODULE_ENABLE(_x) \
    __I2Cx(_x)##CONLbits.I2CEN = 1

但这会产生如下输出:I2C1 CONLbits .I2CEN = 1,而我的编译器抱怨 I2C1CONLbits 标记之间的空格。

【问题讨论】:

    标签: c macros header-files libraries


    【解决方案1】:

    正如我所见,您没有正确添加宏级别。通常的习惯用法是定义一个除了转发参数什么都不做的包装器。这样,如果参数本身是一个宏,它将在传递给被包装的宏之前进行扩展:

    #define I2C_MODULE_ENABLE__(x_) \
        I2C##x_##CONLbits.I2CEN = 1
    
    #define I2C_MODULE_ENABLE(x_) \
        I2C_MODULE_ENABLE__(x_)
    

    我冒昧地重命名了您的宏参数,因为带有前导下划线的标识符被定义为为实现保留,我认为安全总比抱歉好。


    为了解决您的空间问题,我会使用众所周知的间接级别,并使用宏之类的函数来生成正确的前缀标记,并将其传递到两个级别以确保它正确扩展:

    #define I2Cx__(x_) I2C##x_
    #define I2C_MODULE_ENABLE__(IC_) \
        IC_##CONLbits.I2CEN = 1
    #define I2C_MODULE_ENABLE_(IC_) \
        I2C_MODULE_ENABLE__(IC_)
    #define I2C_MODULE_ENABLE(x_) \
        I2C_MODULE_ENABLE_(I2Cx__(x_))
    

    现场观看here

    整个问题是确保预处理器在每一步都能看到并生成有效的令牌。这可能有点烦人。

    【讨论】:

    • 这并不能真正解决问题/回答问题。
    • @melpomene - 我最终到达了那里。在我最喜欢的云编译器上验证代码示例时遇到问题:)
    • @melpomene - OP 的尝试也是如此。为什么你认为它不应该?
    • "我的问题是:有没有更优雅的解决方案来解决这个问题,因为我有多个寄存器,例如 CONLbits 寄存器。使用这种方法,我需要定义一个每个寄存器都有特殊的 __I2CxREGISTER(_x) 宏。"
    • @MarkoGulin - C 标准不允许它,尽管一些编译器允许它用于某些目标体系结构。我还想说可以在技术上使用前导下划线,只是要小心不要违反规则(因为它们在C FAQ for instnace 中定义)。我的全面警告是因为我觉得不值得大惊小怪,只是避免那些名字。但是,如果您真的觉得没有其他方法适合您,请尝试遵守常见问题解答中的指南。
    猜你喜欢
    • 2014-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    相关资源
    最近更新 更多