9

我正在尝试定义一个宏来生成一个包含变量的令牌名称。

基本上,我正在尝试的是:

#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

4 回答 4

9

我认为您尝试做的事情是不可能的。C 宏实际上是在编译之前扩展的预处理器宏。变量port, 直到运行时才被设置。

于 2010-09-03T04:27:26.273 回答
6

是不可能的。C 预处理器通过处理标记来工作,它们不执行任何需要了解语言机制的解析或替换(除了涉及整数文字的基本算术,我不知道)。例如,考虑 GCC 的预处理器关于 tokenisation的文档。只有编译器会知道如何处理变量“port”。

一种解决方案是执行以下操作:

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

...然后...

int port;
PxDIR(port, 2);

我把它留给你,让它不像这里那样丑陋或骇人听闻(更笼统,取决于你的需要):)

于 2010-09-03T04:32:12.863 回答
5

...或者只是使 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;
}
于 2010-09-06T08:08:59.970 回答
0

你试图做的事情没有意义。

#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 函数返回的空指针。

于 2017-03-08T01:37:15.320 回答