Условная компиляция в зависимости от аргумента функции? - PullRequest
5 голосов
/ 29 ноября 2011

Я искал повсюду, и информация в сети, кажется, предполагает, что условная компиляция с использованием препроцессора работает исключительно с переменными среды.

По сути, я хотел бы, чтобы встроенная функция или макрос выполняли различные операции на основево входных аргументах.Пример того, чего я хочу достичь:

inline void foo(int x) {

    #if (x < 32)

        register0 |= (1 << x);

    #else

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

    #endif

}

Основная цель здесь заключается в том, чтобы полученный встроенный код не содержал условный код для постоянных входных данных.

По сути, в настоящее время я программирую для микроконтроллера(lpc213x) и хотел бы иметь встроенную функцию или макрос для настройки конфигурации выводов.Поскольку конфигурации выводов разделены на несколько регистров (например, 0 и 1 выше), я хотел бы выполнить некоторые условные проверки, чтобы решить, в какой регистр следует записать данные для данной константы вывода.

Однако выводвсе конфигурации являются постоянными во время компиляции, поэтому я хотел бы исключить условные проверки из кода компиляции.Я знаю, что оптимизация, скорее всего, избавит от ненужных условий в любом случае, но мне интересно, есть ли способ явно реализовать это поведение, потому что мне может понадобиться отключить оптимизацию в будущем.

Спасибо,

FRob

Ответы [ 6 ]

6 голосов
/ 29 ноября 2011

С 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>();
}
3 голосов
/ 29 ноября 2011

Вот ужасный способ для 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
2 голосов
/ 03 января 2012

Вы можете удалить условный код, используя оценку короткого замыкания трюк:

void foo(int x) {
  x < 32 && (register0 |= (1 << x));
  x >= 32 && (register1 |= (1 << (x - 32)));
}
2 голосов
/ 29 ноября 2011

И если вы кодируете на C, единственное, что вы можете сделать, это определить две версии foo ().

1 голос
/ 29 ноября 2011

попробуйте

#define X 15 // or some else

#if X <= 32
#   define SET_X register0 |= (1 << X)
#else
#   define SET_X register1 |= (1 << (x - 32))
#endif
0 голосов
/ 12 августа 2014

Если вы используете препроцессор 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;
}
...