【问题标题】:What is the difference between #define name and #define name(arguments) when it comes to #ifdef name or #if defined(name) in C?#define name 和 #define name(arguments) 在 C 中的 #ifdef name 或 #if defined(name) 有什么区别?
【发布时间】:2020-11-10 16:00:31
【问题描述】:

我在嵌入式 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, interrupt)... 运行预处理后生成的数组是这些

 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

【问题讨论】:

  • #ifdef#if defined 之间的唯一区别是 #ifdef 需要的字母更少。
  • @ThomasMatthews:对于拥有#if defined X && Y == 3 并将其更改为#ifdef X && Y == 3 的人来说,这将是一个惊喜。
  • #ifdef 预处理器指令测试符号(宏)是否已定义(或已存在)。它不测试符号的值。
  • @ThomasMatthews 在简单的情况下是正确的,但 ANSI C(又名 C89)引入的 #if defined 语法允许更复杂的测试,例如:#if (defined XX || defined YY) && !defined ZZ
  • 看起来是如何编写英国媒体报道软件的完美示例。在初始化列表中间使用包含是简单的可怕设计。更好的设计可能是创建两个或多个结构初始化器列表,然后根据 #ifdef 使用结构的相关初始化器列表。 KISS 原则。

标签: c macros embedded


【解决方案1】:

“config.h”中的代码似乎是为一些早期代码设计的,用于定义CONFIG_PERIPH_0CONFIG_PERIPH_1,但不能同时定义两者。

如果定义了CONFIG_PERIPH_0,则此代码将CONFIG_PERIPH_1 定义为空——CONFIG_PERIPH_1(…) 的任何使用都将替换为空(空令牌列表)。相反,如果定义了CONFIG_PERIPH_1,则此代码将CONFIG_PERIPH_0 定义为null。

那么代码同时使用了CONFIG_PERIPH_0CONFIG_PERIPH_1,知道之前代码定义的那个会被替换成定义的,另一个无效。

宏是定义为类对象 (#define foo replacement-tokens) 还是类函数 (#define foo(argument) replacement-tokens) 与 defined 运算符或 #ifdef 指令无关。如果以任一方式定义宏,defined 运算符的计算结果为真。如果未定义,则运算符评估为 false。

【讨论】:

    【解决方案2】:

    宏是否接受参数并不影响它是否被定义。仅名称就是您为 defined 测试的内容,参数无关紧要,因为宏未在 #ifdef / #if defined 测试中展开。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多