【问题标题】:Conditional compilation depending on function argument?取决于函数参数的条件编译?
【发布时间】:2011-11-29 10:54:45
【问题描述】:

我进行了广泛搜索,网上的信息似乎表明使用预处理器的条件编译仅适用于环境变量。

基本上,我希望有一个内联函数或宏根据其输入参数执行不同的操作。我想要实现的示例:

inline void foo(int x) {

    #if (x < 32)

        register0 |= (1 << x);

    #else

        register1 |= (1 << (x - 32));

    #endif

}

这里的主要目标是生成的内联代码将不包含用于常量输入的条件代码。

基本上,我目前正在为微控制器 (lpc213x) 编程,并希望有一个内联函数或宏来进行引脚配置设置。由于引脚配置被拆分到多个寄存器(例如上面的 0 和 1),我想执行一些条件检查来决定应该为给定的引脚常量写入哪个寄存器。

但是,引脚配置在编译时都是不变的,所以我想从编译代码中消除条件检查。我知道优化可能会摆脱不必要的条件,但我想知道是否有办法明确地实现这种行为,因为我将来可能需要禁用优化。

谢谢,

FRob

【问题讨论】:

  • 如果您使用 C++,您可以使用模板解决此问题。不要标记您的问题 C 和 C++,除非您确实遇到与这两种语言有关的问题。
  • 在你的编译器中启用优化,它会神奇地为你做这件事。或者在 C++ 中使用constexpr
  • 应该是x &lt; 32,而不是x &lt;= 321 应该是1U)。
  • 抱歉,我将其标记为 C++,因为我认为它也与 C++ 预处理器有关。根据您的建议未标记 C++。

标签: c c-preprocessor


【解决方案1】:

使用 C++,您可以使用模板函数,如下所示:

template <bool B>
void doSetRegister(int x);

template<>
inline void doSetRegister<true>(int x) {
    register0 |= (1 << x);
}

template<>
inline void doSetRegister<false>(int x) {
    register1 |= (1 << (x - 32));
}

template <int X>
inline void setRegister() {
    doSetRegister<X <= 32>(X);
}

int main() {
    setRegister<1>();
    setRegister<33>();
}

【讨论】:

    【解决方案2】:

    这是 C 的一种丑陋方式:

    #include <stdio.h>
    
    volatile unsigned long register0 = 0, register1 = 0;
    
    #define DEF0X(_X_) \
      static inline void SetPin##_X_() { register0 |= 1ul << _X_; }
    
    #define DEF1X(_X_) \
      static inline void SetPin##_X_() { register1 |= 1ul << (_X_ - 32); }
    
    DEF0X(0)  DEF0X(1)  DEF0X(2)  DEF0X(3)  DEF0X(4)
    DEF0X(5)  DEF0X(6)  DEF0X(7)  DEF0X(8)  DEF0X(9)
    DEF0X(10) DEF0X(11) DEF0X(12) DEF0X(13) DEF0X(14)
    DEF0X(15) DEF0X(16) DEF0X(17) DEF0X(18) DEF0X(19)
    DEF0X(20) DEF0X(21) DEF0X(22) DEF0X(23) DEF0X(24)
    DEF0X(25) DEF0X(26) DEF0X(27) DEF0X(28) DEF0X(29)
    DEF0X(30) DEF0X(31) DEF1X(32) DEF1X(33) DEF1X(34)
    DEF1X(35) DEF1X(36) DEF1X(37) DEF1X(38) DEF1X(39)
    DEF1X(40) DEF1X(41) DEF1X(42) DEF1X(43) DEF1X(44)
    DEF1X(45) DEF1X(46) DEF1X(47) DEF1X(48) DEF1X(49)
    DEF1X(50) DEF1X(51) DEF1X(52) DEF1X(53) DEF1X(54)
    DEF1X(55) DEF1X(56) DEF1X(57) DEF1X(58) DEF1X(59)
    DEF1X(60) DEF1X(61) DEF1X(62) DEF1X(63)
    
    #define SET_PIN(_X_) SetPin##_X_()
    
    int main(void)
    {
      SET_PIN(0);
      SET_PIN(1);
      SET_PIN(32);
      SET_PIN(63);
      printf("register0=0x%08lX register1=0x%08lX\n",
             register0, register1);
      return 0;
    }
    

    输出:

    register0=0x00000003 register1=0x80000001
    

    【讨论】:

    • 所以有可能 :D 虽然我同意这有点难看,但我认为使用组合 SET_PIN 函数的整体功能很棒 :D 谢谢!
    【解决方案3】:

    如果你用 C 编码,你唯一能做的就是定义两个版本的 foo()。

    【讨论】:

      【解决方案4】:

      您可以使用short-circuit evaluation 技巧删除条件代码:

      void foo(int x) {
        x < 32 && (register0 |= (1 << x));
        x >= 32 && (register1 |= (1 << (x - 32)));
      }
      

      【讨论】:

        【解决方案5】:

        试试这个

        #define X 15 // or some else
        
        #if X <= 32
        #   define SET_X register0 |= (1 << X)
        #else
        #   define SET_X register1 |= (1 << (x - 32))
        #endif
        

        【讨论】:

          【解决方案6】:

          如果您使用 C 预处理器创建一组由两个无符号长整数组成的定义,然后将它们用作函数 foo() 的参数,则代码非常简单。如果您需要添加另一个寄存器,您可以修改定义。

          #define PIN_00  0x00000001, 0x00000000
          #define PIN_01  0x00000002, 0x00000000
          // defines left out here
          #define PIN_31  0x80000000, 0x00000000
          #define PIN_32  0x00000000, 0x00000001
          // defines left out here
          #define PIN_63  0x00000000, 0x80000000
          
          inline void foo (unsigned long reg1, unsigned long reg2)
          {
              register0 |= reg1;
              register1 |= reg2;
          }
          

          然后要使用此功能foo(),您将指定适当的定义。由于与零进行按位或运算不会发生任何变化,因此寄存器将被适当地更新。

          foo (PIN_00);
          foo (PIN_01);
          foo (PIN_32);
          foo (PIN_63);
          

          如果您需要添加一种删除位的方法,您可以使用以下相同的定义创建一个新函数:

          inline void fooRemove (unsigned long reg1, unsigned long reg2)
          {
              register0 &= ~reg1;
              register1 &= ~reg2;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-23
            • 1970-01-01
            • 1970-01-01
            • 2021-08-01
            • 2010-09-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多