#define name 和 #define name(arguments) 在 C 中涉及 #ifdef name 或 #if defined(name) 时有什么区别?
What is the difference between #define name and #define name(arguments) when it comes to #ifdef name or #if defined(name) in C?
我已经在一个嵌入式 C 项目上工作了几天,我发现了一些使用大量宏的有趣配置文件。
代码如下所示
// config.h
//?????
#if defined(CONFIG_PERIPH_0)
#define CONFIG_PERIPH_1(ch, interrupt)
#elif defined(CONFIG_PERIPH_1)
#define CONFIG_PERIPH_0(ch, interrupt)
#endif
CONFIG_PERIPH_0(PERIPH_INPUTCHAN_28, FALSE)
CONFIG_PERIPH_0(PERIPH_INPUTCHAN_27, FALSE)
CONFIG_PERIPH_1(PERIPH_INPUTCHAN_29, TRUE)
CONFIG_PERIPH_1(PERIPH_INPUTCHAN_30, FALSE)
//?????
#undef CONFIG_PERIPH_0
#undef CONFIG_PERIPH_1
// periph.h
#include "config.h"
#define CONFIG_PERIPH_0(ch, interrupt) { \
.interruptEnable = interrupt, \
.channel = ch \
},
periph_chan_config_t const PERIPH0_Array_Chs[] = {
#include "config.h" // the contents of "config.h" file is copied here
{FALSE, 0};
};
#define CONFIG_PERIPH_1(ch, interrupt) { \
.interruptEnable = interrupt, \
.channel = ch \
},
periph_chan_config_t const PERIPH1_Array_Chs[] = {
#include "config.h" // the contents of "config.h" file is copied here
{FALSE, 0};
};
#define SIZE_PERIPH0_ARRAY (sizeof(PERIPH0_Array_Chs)/sizeof(PERIPH0_Array_Chs[0]))
#define SIZE_PERIPH1_ARRAY (sizeof(PERIPH1_Array_Chs)/sizeof(PERIPH1_Array_Chs[0]))
我不明白这些里面究竟发生了什么//?????? //?????? config.h 中的“标签”。
另外我不确定 #if defined(CONFIG_PERIPH_0) 是否被评估为 TRUE 或 FALSE 因为在它之前,有 #define CONFIG_PERIPH_0 (ch, 中断)...
运行 预处理后生成的数组是这些
periph_chan_config_t const PERIPH0_Array_Chs[] = {
{ .interruptEnable = 0u, .channel = PERIPH0_INPUTCHAN_28 },
{ .interruptEnable = 0u, .channel = PERIPH0_INPUTCHAN_27 },
{0u, 0};
};
periph_chan_config_t const PERIPH1_Array_Chs[] = {
{ .interruptEnable = 1u, .channel = PERIPH1_INPUTCHAN_29 },
{ .interruptEnable = 0u, .channel = PERIPH1_INPUTCHAN_30 },
{0u, 0};
};
我写了一个例子来强调 #define name 和 #define name(args) 在评估 #ifdef name 或 #if defined(name) 在这两种情况下 MACROS
“config.h”中的代码似乎是为某些早期代码设计的,用于定义 CONFIG_PERIPH_0
或 CONFIG_PERIPH_1
,但不能同时定义两者。
如果定义了 CONFIG_PERIPH_0
,则此代码将 CONFIG_PERIPH_1
定义为空——任何对 CONFIG_PERIPH_1(…)
的使用都将被替换为空(一个空标记列表)。相反,如果定义了 CONFIG_PERIPH_1
,则此代码将 CONFIG_PERIPH_0
定义为 null。
那么代码中同时使用了CONFIG_PERIPH_0
和CONFIG_PERIPH_1
,知道前面代码定义的那个会被替换成定义的,另一个就没有效果了。
宏定义为类对象 (#define foo replacement-tokens
) 还是类函数 (#define foo(argument) replacement-tokens
) 与 defined
运算符或 #ifdef
指令无关.如果以任一方式定义宏,则 defined
运算符的计算结果为真。如果未定义,则运算符计算为 false。
宏是否带参数不影响它是否被定义。名称本身就是您为 defined 测试的内容,参数无关紧要,因为宏未在 #ifdef / #if defined 测试中扩展。
我已经在一个嵌入式 C 项目上工作了几天,我发现了一些使用大量宏的有趣配置文件。
代码如下所示
// config.h
//?????
#if defined(CONFIG_PERIPH_0)
#define CONFIG_PERIPH_1(ch, interrupt)
#elif defined(CONFIG_PERIPH_1)
#define CONFIG_PERIPH_0(ch, interrupt)
#endif
CONFIG_PERIPH_0(PERIPH_INPUTCHAN_28, FALSE)
CONFIG_PERIPH_0(PERIPH_INPUTCHAN_27, FALSE)
CONFIG_PERIPH_1(PERIPH_INPUTCHAN_29, TRUE)
CONFIG_PERIPH_1(PERIPH_INPUTCHAN_30, FALSE)
//?????
#undef CONFIG_PERIPH_0
#undef CONFIG_PERIPH_1
// periph.h
#include "config.h"
#define CONFIG_PERIPH_0(ch, interrupt) { \
.interruptEnable = interrupt, \
.channel = ch \
},
periph_chan_config_t const PERIPH0_Array_Chs[] = {
#include "config.h" // the contents of "config.h" file is copied here
{FALSE, 0};
};
#define CONFIG_PERIPH_1(ch, interrupt) { \
.interruptEnable = interrupt, \
.channel = ch \
},
periph_chan_config_t const PERIPH1_Array_Chs[] = {
#include "config.h" // the contents of "config.h" file is copied here
{FALSE, 0};
};
#define SIZE_PERIPH0_ARRAY (sizeof(PERIPH0_Array_Chs)/sizeof(PERIPH0_Array_Chs[0]))
#define SIZE_PERIPH1_ARRAY (sizeof(PERIPH1_Array_Chs)/sizeof(PERIPH1_Array_Chs[0]))
我不明白这些里面究竟发生了什么//?????? //?????? config.h 中的“标签”。 另外我不确定 #if defined(CONFIG_PERIPH_0) 是否被评估为 TRUE 或 FALSE 因为在它之前,有 #define CONFIG_PERIPH_0 (ch, 中断)... 运行 预处理后生成的数组是这些
periph_chan_config_t const PERIPH0_Array_Chs[] = {
{ .interruptEnable = 0u, .channel = PERIPH0_INPUTCHAN_28 },
{ .interruptEnable = 0u, .channel = PERIPH0_INPUTCHAN_27 },
{0u, 0};
};
periph_chan_config_t const PERIPH1_Array_Chs[] = {
{ .interruptEnable = 1u, .channel = PERIPH1_INPUTCHAN_29 },
{ .interruptEnable = 0u, .channel = PERIPH1_INPUTCHAN_30 },
{0u, 0};
};
我写了一个例子来强调 #define name 和 #define name(args) 在评估 #ifdef name 或 #if defined(name) 在这两种情况下 MACROS
“config.h”中的代码似乎是为某些早期代码设计的,用于定义 CONFIG_PERIPH_0
或 CONFIG_PERIPH_1
,但不能同时定义两者。
如果定义了 CONFIG_PERIPH_0
,则此代码将 CONFIG_PERIPH_1
定义为空——任何对 CONFIG_PERIPH_1(…)
的使用都将被替换为空(一个空标记列表)。相反,如果定义了 CONFIG_PERIPH_1
,则此代码将 CONFIG_PERIPH_0
定义为 null。
那么代码中同时使用了CONFIG_PERIPH_0
和CONFIG_PERIPH_1
,知道前面代码定义的那个会被替换成定义的,另一个就没有效果了。
宏定义为类对象 (#define foo replacement-tokens
) 还是类函数 (#define foo(argument) replacement-tokens
) 与 defined
运算符或 #ifdef
指令无关.如果以任一方式定义宏,则 defined
运算符的计算结果为真。如果未定义,则运算符计算为 false。
宏是否带参数不影响它是否被定义。名称本身就是您为 defined 测试的内容,参数无关紧要,因为宏未在 #ifdef / #if defined 测试中扩展。