我在C中编写了以下宏:
#define __HAL_CLK_ENABLE(CONTROL_STRUCT,REG,CLK) do { \
SET_BIT(CONTROL_STRUCT->REG,##CONTROL_STRUCT##_##REG##_##CLK##EN);\
} while(0)
main.c /中的宏调用所有参数都在cpu特定的头文件中定义:
__HAL_CLK_ENABLE(RCC,AHB1ENR,GPIOA);
结果应为:
SET_BIT(RCC->AHB1ENR,RCC_AHB1ENR_GPIOAEN)
此宏可以正常工作并启用我的GPIOA端口,但是我收到两条编译器警告。 (IAR EW 7.6)
2。在宏“__HAL_CLK_ENABLE”中与“RCC_AHB1ENR_GPIOAEN”串联不会创建有效的令牌。 (这是什么意思?因为令牌工作正常并且在调用此宏后启用了我的时钟)
由于
EDIT1:
宏定义:
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define RCC ((RCC_TypeDef *) RCC_BASE)
typedef struct
{
...
__IO uint32_t AHB1ENR;
...
} RCC_TypeDef;
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
答案 0 :(得分:1)
“#和##运算符的评估顺序未指定。”(ISO C99 / C11 6.10.3.2,6.10.3.3)意味着宏可能会使编程器意图使用一个编译器而不是另一个编译器失败。
在你的情况下,这不是什么大问题,正如Ouss4提到的那样,MISRA-C建议不要使用多个#或##运算符,主要是为了避免混淆(因此它只是一个咨询指南)。
但是,如果##操作导致无效令牌,则可能的多个##运算符可能导致未定义的行为,这就是IAR警告的内容。在MISRA-C论坛上"Rule 19.12 (# and ## operator) real issue?”讨论了这个简单的例子:
define m(a,b) a##.##b
m(1,e30)
是从左到右评估的定义行为,但未定义 从右到左的行为,因为.e30是两个预处理标记。
答案 1 :(得分:0)
在##CONTROL_STRUCT##_##REG##_##CLK##EN
中删除第一个##
。
请注意,您正在做的事情容易出错,嵌入式编码标准不推荐这样做。
MISRA C:
规则19.12(必填):最多应出现一次#或##运算符 单个宏定义。
规则19.13(咨询):不应使用#和##运算符。