基于#define名称的条件语句

时间:2016-08-07 19:32:18

标签: c arm stm32

我刚刚开始做一些C(来自Java)。我试图找出基于定义名称的语言对条件的处理方式。

e.g。我有一个巨大的头文件,我不能(不应该)编辑很多定义。

#define GPIO_OTYPER_OT_0                     ((uint32_t)0x00000001)
#define GPIO_OTYPER_OT_1                     ((uint32_t)0x00000002)
#define GPIO_OTYPER_OT_2                     ((uint32_t)0x00000004)
#define GPIO_OTYPER_OT_3                     ((uint32_t)0x00000008)
#define GPIO_OTYPER_OT_4                     ((uint32_t)0x00000010)
#define GPIO_OTYPER_OT_5                     ((uint32_t)0x00000020)

等等;

我想对函数/声明(或解决方案的任何内容)进行操作,以对作为定义的_#部分进行操作。

(伪代码)

void initialize(int X) {
  GPIOA->MODER |= GPIO_MODER_MODER%X_5;
  GPIOA->OTYPER &= ~GPIO_OTYPER_OT_%X;
  GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR%X;
  GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5;
  GPIOA->ODR |= GPIO_ODR_ODR_%X;
}

%X是int X

我能想到的只是每个X的switch语句,但X的范围很大,因此源文件会很大。

编辑: https://github.com/espruino/Espruino/blob/master/targetlibs/stm32f4/lib/stm32f411xe.h 是头文件。

2 个答案:

答案 0 :(得分:1)

无法在宏名称中插入任意整数。但是,你的整数会很小(肯定小于32,因为所有的常量都是32位类型)。因此,您可以将switch语句转换为单行表达式,如下所示:

x == 0 ? GPIO_OTYPER_OT_0 : \
x == 1 ? GPIO_OTYPER_OT_1 : \
x == 2 ? GPIO_OTYPER_OT_2 : \
...
x == 31 ? GPIO_OTYPER_OT_31 : 0

在这里,您甚至可以制作"默认"将生成运行时错误的表达式 - 类似于(abort(), (uint32_t)0)

为了使其更通用,将GPIO_OTYPER_OT_部分分成宏参数,并使用"粘贴运算符" ##

#define MY_MACRO(name, x) \
x == 0 ? name ## 0 : \
x == 1 ? name ## 1 : \
x == 2 ? name ## 2 : \
...
x == 31 ? name ## _31 : \
(abort(), name ## 0)

用法示例:

GPIOA->ODR |= MY_MACRO(GPIO_ODR_ODR_, x);

您必须为中间位置为x的名称创建单独的宏:

#define MY_MACRO2(prefix, x, suffix) ( \
(x) == 0 ? prefix ## 0 ## suffix : \
(x) == 1 ? prefix ## 1 ## suffix : \
...
(x) == 31 ? prefix ## 31 ## suffix : \
(abort(), prefix ## 0 ## suffix))

在这里,我还添加了必要的括号(在x附近和整个宏周围),就像它是C宏的习惯一样。

P.S。如果您的大型头文件没有定义数字最多为31但具有较小限制的宏,则不能使用提及所有这些名称的宏,因为您会收到编译错误。在这种情况下,将最大值插入宏的名称。然后你可以在"递归"中定义它们。方式:

#define MY_MACRO_MAX1(prefix, x) \
x == 0 ? prefix ## 0 ## suffix : prefix ## 1 ## suffix

#define MY_MACRO_MAX2(prefix, x) \
x == 2 ? prefix ## 2 ## suffix : MY_MACRO_MAX1(prefix, x)

#define MY_MACRO_MAX3(prefix, x) \
x == 3 ? prefix ## 3 ## suffix : MY_MACRO_MAX2(prefix, x)

#define MY_MACRO_MAX4(prefix, x) \
x == 4 ? prefix ## 4 ## suffix : MY_MACRO_MAX3(prefix, x)

#define MY_MACRO_MAX5(prefix, x) \
x == 5 ? prefix ## 5 ## suffix : MY_MACRO_MAX4(prefix, x)

...

答案 1 :(得分:1)

使用ST的GPIO抽象层,可以找到here。值得注意的是,请参阅GPIO_InitTypeDef,它为您提供上述内容的结构,GPIO_Init实际上可以执行您想要的操作。初始化结构将引脚作为位掩码,因此在注释中建议使用@artless噪声,您只需执行1<<X即可创建掩码。所有特定于MCU的行为和寄存器映射都隐藏在您的代码之外。

如果您尝试将自己的驱动程序层实现为练习,或者因为您认为ST库不是很好,那么我仍然会看看它们在C file中如何实现GPIO_Init }。他们使用移位,但你会注意到在处理寄存器时,它并不总是像1<<X那么容易(但请注意,对于他们的配置结构, 总是那么容易) 。有些寄存器每个引脚有多个位(模式:2位,拉配置:2位,备用功能:4位,分为多个寄存器)。

编辑:我不建议添加更多您尚未拥有的库。您引用头文件的库/代码库已包含ST的外设库,因此使用它是有意义的(对我而言)。

相关问题