c - 使用##连接宏常量

标签 c macros header-files libraries

我正在为微 Controller 编写一些库,为此,我使用类似宏的函数。例如,启用 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 ,我的编译器提示 I2C1 之间的空格和CONLbits代币。

最佳答案

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

#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

整个技巧是确保预处理器在每一步都能看到并生成有效的标记。这可能有点无聊。

关于c - 使用##连接宏常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42329052/

相关文章:

c++ - 如何在最前面执行一个头文件?

c++ - 如何使用宏动态加载 dll

c++ - 在 Visual Studio 2013 中使用旧的 Direct X SDK

visual-studio - 在 Visual Studio 中运行宏时获取光标位置

BZ2_bzBuffToBuffCompress()可以重复调用吗?

c - 我在哪里可以找到在 c 标准头文件(如 stdlib.h)中声明的函数的定义?

c - header 编译错误中的结构

c - API用于检查有关CPU、内存、网络、NAT表使用情况的信息

python - 杀死由python脚本执行的C程序

c - 如何跟踪 malloc 和 free?