【问题标题】:C Macro Token Concatenation involving a variable - is it possible?涉及变量的 C 宏标记连接 - 可能吗?
【发布时间】:2011-04-07 16:14:00
【问题描述】:

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

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

#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吗?

标签: c concatenation token c-preprocessor stringification


【解决方案1】:

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

【讨论】:

  • 谢谢,我就是这么想的。我已经有一段时间没有直接做 C 了。
【解决方案2】:

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

一种解决方案是:

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

...后来...

int port;
PxDIR(port, 2);

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

【讨论】:

  • 谢谢。我正在研究它作为减少嵌入式项目中代码膨胀的一种方法,但看起来好像不可能使用变量来解决这个问题。呃,好吧。再次感谢!
  • @user438605 确实如此——尽管您可能想查看X Macro Idiom 以进行重复代码生成。
【解决方案3】:

...或者只是让 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;
}

【讨论】:

    【解决方案4】:

    您尝试做的事情没有意义。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-24
      • 1970-01-01
      • 2020-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多