define对于用过C语言的同学应该都不陌生,常用的就是宏定义,可以用作开关,也可以用作参数定义。实际除了简单的参数定义外,还有一些特殊的符号,可以实现一些“骚操作”
当我们想用一个宏定义来控制一段代码是否参与编译,也可以说一个功能是否启用(功能对应的代码都加上了对应的宏定义)可以使用宏开关的方式实现
示例如下:我们定义一个LED_Ctrl的功能
#define LED_Ctrl
#ifdef LED_Ctrl
IoHwAb_Led_Ctrl(Led0,STD_ON);
....
#endif
通过定义和取消定义该宏定义,即可实现该功能是否启用,在项目前期调试过程中,会经常用到。量产交付时,应尽可能减少该类宏定义。
通过宏定义替换参数,可以实现在多个地方使用同一个参数时,方便修改。
示例如下:
# define AdcHwUnit_NUM ( 3U)
for(Index = 0; Index < AdcHwUnit_NUM; Index++)
{
....
}
使用宏函数可以实现一些判断逻辑或计算公式。常用的如MAX,MIN,ABS宏函数
#define MAX(a,b) (a>b)?a:b
...
max=MAX(x,y);
宏函数在MISRA中建议不要使用。具体可以参考规范。
##表示连接,在宏定义中,使用##可以实现传递参数,而实现不同的函数定义,在RH850P1HC的MCAL中有类似的定义:
#define DIO_ENTER_CRITICAL_SECTION(Exclusive_Area) \
SchM_Enter_Dio_##Exclusive_Area()
DIO_ENTER_CRITICAL_SECTION(DIO_REGISTER_PROTECTION);
最终函数实现:SchM_Enter_Dio_DIO_REGISTER_PROTECTION();
调用函数时传递的名称不同,最终出来的函数也不一样。
还有一种用法,可以改变输入的参数,实现不同的定义输入:
例如,我们在MCAL中定义了两个Sequence,一个TEST_One_SpiSequence,一个TEST_Two_SpiSequence,通过如下宏定义:
#define Spi_SyncTransmit_Abstract(name) Spi_SyncTransmit(TEST_##name##_SpiSequence)
我们调用Spi_SyncTransmit_Abstract(One);时,最终发送的就是TEST_One_SpiSequence
当调用Spi_SyncTransmit_Abstract(Two);时,发送的就是TEST_Two_SpiSequence
当宏定义太长,需要换行时,就需要用到\,该符号应该在头文件中很常见。
#define DIO_DBTOC_VALUE ((((uint32)DIO_VENDOR_ID) << (uint32)22) | \
(((uint32)DIO_MODULE_ID) << (uint32)14) | \
(((uint32)DIO_SW_MAJOR_VERSION) << (uint32)8) | \
(((uint32)DIO_SW_MINOR_VERSION) << (uint32)3))
注意:最后一行不要加续行符
"#@"是给参数加上单引号。这个在嵌入式中应该用的比较少
#define TOCHAR(a) #@a /* TOCHAR(1) => '1' */