【问题标题】:How do you test if two #defines are the same with the C preprocessor你如何测试两个#defines是否与C预处理器相同
【发布时间】:2014-07-08 14:05:30
【问题描述】:

我有一个 C 程序,它具有特定于平台的定义,用于访问低级硬件。在某些平台上,两个宏指向同一个变量,而在其他平台上它们是不同的:

 //Platform_One.h
 #define FOO_PORT   (io.portA)
 #define BAR_PORT   (io.portB)

 //Platform_Two.h
 #define FOO_PORT   (io.portC)
 #define BAR_PORT   (io.portC)  //same

根据#defines 是否相同,我有一些不同的初始化代码。从概念上讲,我想要这样的代码:

 callback_struct_t callbacks[] = {
 #if FOO_PORT == BAR_PORT           //unfortunately invalid
     {&FOO_PORT, handle_foo_bar_func},
 #else
     {&FOO_PORT, handle_foo_func},
     {&BAR_PORT, handle_bar_func},
 #endif          
      {0,0}
 };

如果两个任意宏具有相同的定义,是否有可靠的方法在编译时进行测试?

【问题讨论】:

  • 平台是否没有提供任何其他宏来指示正在为哪个平台编译代码?
  • 您能否为平台 2 设置一个标志 #define 以指示端口是共享的,然后在填充 callbacks 数组时测试该标志?
  • 我认为您必须通过代码(即在运行时)初始化 callbacks 数组。在全局变量的情况下 - 是的,这是一段额外的代码,但鉴于它只运行一次,它不太可能影响应用程序的整体性能。在局部变量的情况下,无论如何都会发生“代码初始化”,因为每次调用函数时数组都必须保留其初始值。因此,即使您确实有一些“神奇”的方法来使用宏,它也不会产生重大影响(最多会为您节省额外的if)。
  • 我看不出链接的问题是如何相关的。我的#defines 不是字符串,它们是变量名(或者可能是它们的地址)。
  • 可能的重复与它描述在 C 预处理器中比较纯(整数)数字表达式以外的事物有关 - 并且在某种程度上它有相同的答案:不,你可以不要这样做。 C 预处理器是一个有趣的工具,但它有局限性,而您正在寻求超越这些局限性。

标签: c c-preprocessor


【解决方案1】:

您不能将预处理器宏作为字符串进行比较。一种可能性是将硬件端口地址(例如,通过平台特定标头中的另一个宏)放入#defines,然后比较地址。

但是,最简单的方法可能是在实际代码中进行地址比较,例如:

if (&FOO_PORT == &BAR_PORT) {
    // populate callbacks with handle_foo_bar_func
} else {
    // populate callbacks with handle_foo_func and handle_bar_func
}

虽然未在预处理器中完成,但编译器可能能够优化掉未使用的分支,因为硬件地址可能是编译时常量。

【讨论】:

    【解决方案2】:

    使用 gnu c 处理器可以完成字符串化:https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification

    你可以这样做:

    #include <stdio.h>
    #include <string.h>
    
    #define FOO_PORT   (io.portA)
    #define BAR_PORT   (io.portB)
    
    //#define FOO_PORT   (io.portC)
    //#define BAR_PORT   (io.portC)
    
    #define XMACRO_TEST(macro_a, macro_b) MACRO_TEST(macro_a, macro_b)
    
    #define MACRO_TEST(macro_a, macro_b) \
        if(strcmp((#macro_a),(#macro_b)) == 0) { \
            printf(#macro_a" == "#macro_b"\n"); \
        } else { \
            printf(#macro_a" != "#macro_b"\n"); \
        } \
    
    int main(int argc, char *argv[])
    {
        XMACRO_TEST(FOO_PORT, BAR_PORT)
    
        return 0;
    }
    

    【讨论】:

    • 简洁,但这并不是他想要的:他想要一个编译时条件#IF而不是代码if,不幸的是它用于结构初始化,所以你不能使用if并依赖一个分支被编译出来。
    【解决方案3】:

    您可以比较计算结果为整数的宏。 我的理解是你有三种选择:

    • 更改宏逻辑
    • 对端口号宏使用数值(它们是物理地址吗?)
    • 用 c 代码填充回调结构,作为 cmets 建议之一。

    最后一个选项似乎是最有利的。如果正确使用 const,无论如何,大多数编译器都会在编译时进行计算。

    【讨论】:

      猜你喜欢
      • 2011-07-02
      • 1970-01-01
      • 2016-02-26
      • 1970-01-01
      • 2010-11-19
      • 2011-06-09
      • 1970-01-01
      • 2017-05-27
      相关资源
      最近更新 更多