C宏令牌串联涉及变量-是否可能?

10
我正在尝试定义一个宏来生成包含变量的令牌名称。
基本上,我正在尝试这样做:
#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,这不是我想要的。有什么帮助吗?或者我尝试做的是不可能的吗?


你是不是想要做 #define port 2 - Gabe
4个回答

9

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


谢谢,这正是我所想的。我已经有一段时间没有写纯C了。 - gatesphere

6

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

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

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

...以及之后...

int port;
PxDIR(port, 2);

我把这个留给你,让它不那么丑陋或者hacky(根据你的需要更加通用):)


谢谢。我正在研究它作为减少嵌入式项目中代码膨胀的一种方式,但看起来无法使用变量来解决这个问题。哎呀,再次感谢! - gatesphere
@user438605 的确如此 - 虽然您可能需要查看X Macro Idiom来进行重复代码生成。 - detly

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;
}

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接