C Макротокен Конкатенация с участием переменной - возможно ли это? - PullRequest
8 голосов
/ 03 сентября 2010

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

По сути, я пытаюсь это:

#define GLUER(x,y,z) x##y##z
#define PxDIR(x) GLUER(P,x,DIR)

int main() {
  int port;
  port = 2;
  PxDIR(port) |= 0x01;
}

Я надеюсьчтобы сгенерировать токен P2DIR в приведенном выше операторе, но, согласно выводу моего компилятора, он генерирует токен PportDIR, что НЕ то, что я хотел.Любая помощь здесь?Или то, что я пытаюсь сделать, невозможно?

Ответы [ 4 ]

9 голосов
/ 03 сентября 2010

Я не думаю, что вы пытаетесь сделать это возможно.Макросы Си - это действительно препроцессорные макросы, которые раскрываются перед компиляцией.Переменная port не устанавливается до времени выполнения.

6 голосов
/ 03 сентября 2010

невозможно. Препроцессоры C работают, обрабатывая токены , и они не делают никакого разрешения или замены, которые потребовали бы знания механики языка (кроме базовой арифметики, включающей целочисленные литералы, вне моей головы). Рассмотрим, например, документы для препроцессора GCC относительно токенизации . Только компилятор будет знать, что делать с переменной «порт».

Одно из решений - сделать что-то вроде:

#define PxDIR(var, portnum) do { \
    var = portnum; \
    P##portnum##DIR |= blah; \
} while(0)

... и позже ...

int port;
PxDIR(port, 2);

Я оставляю вам сделать это не таким уродливым или хакерским, как здесь (и более общим, в зависимости от того, что вам нужно):)

3 голосов
/ 06 сентября 2010

... или просто сделайте PORT также макросом:

#define PORT 2
#define GLUER(x,y,z) x##y##z
#define PxDIR(x) GLUER(P,x,DIR)

int main() {
    PxDIR(PORT) |= 0x01;
    return 0;
}
0 голосов
/ 08 марта 2017

То, что вы пытаетесь сделать, не имеет смысла.

#define GLUER(x,y,z) x##y##z
#define PxDIR(x) GLUER(P,x,DIR)

int main() {
  int port;
  port = 2;
  PxDIR(port) |= 0x01;
}

Препроцессор запускается во время (до) компиляции. Поэтому он не может ничего знать о содержимом переменной port. Препроцессор требует, чтобы все значения, передаваемые в качестве аргументов макросам, были константами. Например, вы можете сделать следующее:

#define GLUER(x,y,z) x##y##z
#define PxDIR(x) GLUER(P,x,DIR)

int main() {
  PxDIR(2) |= 0x01; //setup port 2
}

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

#define GLUER(x,y,z) x##y##z
#define PxDIR(x) GLUER(P,x,DIR)

uint16_t* get_port_pointer(uint8_t port_id) {
  if (port == 0) {
    return &PxDIR(0);
  } else if (port == 1) {
    return &PxDIR(1);
  } else if (port == 2) {
    return &PxDIR(2);
  } else if (port == 3) {
    return &PxDIR(3);
  } else {
    return &0;
  }
}

int main() {
  int port;
  port = 2;

  *(get_port_pointer(port)) |= 0x01;
}

Таким образом, мы проверяем, есть ли код для любого порта от 0 до 3, к которому необходимо получить доступ. Кроме того, теперь мы должны следить за тем, чтобы нулевые указатели возвращались из функции get_port_pointer.

...