【问题标题】:How to test whether an identifier that is accessible only through a #define macro is defined?如何测试是否定义了只能通过#define 宏访问的标识符?
【发布时间】:2015-06-21 07:46:21
【问题描述】:

我有一个#define 将标识符(函数名)映射到这样的新名称:

#define A doStuff

这部分我无能为力,我必须访问“A”,因为实际标识符(此处为 doStuff)可能会更改(这不在我的控制之下)。现在引用的符号(doStuff)可能存在也可能不存在,我想在前一种情况下调用该函数。对于一个简单的函数名称,我可以轻松地测试它:

#ifdef doStuff
    doStuff();
#endif

但是,受限于宏名称,天真地做同样的事情是:

#ifdef A
    A();
#endif

由于名称“A”已定义,而“doStuff”未定义,因此会出错。我想检查宏解析为的名称是否存在,本质上是:

#if defined(the-content-of-A)

但我不能让它工作。

所以我的问题是:有什么方法可以检查是否定义了由宏表示的标识符?如果是,该怎么做?如果没有,是否有解决方法的通用模式?

虽然我不认为这是特定于 C 或 C++ 的,但我想指出,我需要一些适用于 C++ 中定义的标识符“extern C”的东西。解决方案必须独立于平台。

很抱歉,如果之前有人问过这个问题,我找不到它,无论是在谷歌还是在 SO 上。

【问题讨论】:

  • 请注意,您使用#ifdef doStuff 的示例是错误的。您无法在预处理器级别检测 C/C++ 函数的存在。此外,你想识别#define A(即A存在但没有价值)还是#define A unavailable-function
  • 如果目标函数不存在,则根本不应该定义A。然后你就可以用#ifdef检测这个case了。
  • 正如许多人回答的那样,由于预处理器中存在函数,您无法更改行为。但是您可以使用模板元编程来做到这一点,请参阅此处stackoverflow.com/questions/257288/…
  • 感谢您的澄清。我在问题中称为 doStuff 的符号很可能实际上是真实代码中的宏。
  • 所有答案都是当场的,但我只能接受一个。也感谢其他人。

标签: c++ c macros


【解决方案1】:

定义标识符(函数、对象)是在预处理之后发生的,所以在预处理期间你不可能确定函数是否会在以后定义。

您可以做的解决方法是始终在函数旁边定义一个宏:

void A();
#define A_SUPPLIED

然后对此进行测试:

#ifdef A_SUPPLIED
...
#endif

【讨论】:

    【解决方案2】:

    嗯,不。

    我认为您真正的问题是您不了解宏(使用 #define 引入预处理器并在编译的后期实际编译结果之前使用文本替换扩展)和标识符(是无法由预处理器测试的编译时构造)。

    我这么说是因为唯一的办法

    #ifdef doStuff
        doStuff();
    #endif
    

    如果doStuff() 是一个宏,它将像您声称的那样工作。如果 doStuff() 是标识符(例如,函数或变量的名称),它将不起作用。

    例如,在 C++ 中

    #include <iostream>
    
    void doStuff() {std::cout << "Hello\n";}
    
    int main()
    {
        #ifdef doStuff
            doStuff();
        #else
            std::cout << "Bye\n";
        #endif
    }
    

    将打印Bye 而不是Hello。那是因为函数定义不会产生宏,并且不会被#ifdef 检测到。

    唯一的方法是将宏定义为函数的伴侣

     void DoStuff();
     #define DoStuff_DEFINED
    
     #ifdef DoStuff_Defined
         DoStuff();
     #else
         ComplainBitterly();     /*   assumes ComplainBitterly() exists of DoStuff_DEFINED is not defined */
     #endif
    

    【讨论】:

    • 谢谢。我在问题中称为 doStuff 的符号很可能实际上是真实代码中的宏。
    • 如果是宏,可以测试是否使用预处理器。但它不是标识符或“符号”。
    【解决方案3】:

    无论有无宏,都无法确定纯 C 中是否存在标识符(您的 #ifdef doStuff 示例实际上不起作用)。这是因为在宏扩展时,编译器只是进行文本替换;它不知道定义了哪些符号。理想的方法是让您的库头公开一个 A_IS_PRESENT 宏或类似的宏,您可以在此处关闭 #ifdef

    但是,如果这不是一个选项,则可以使用特定于平台的扩展。例如,在 Linux 上,您可以定义一个弱符号,然后确定它是否被真实交易覆盖:

    #ifdef __cplusplus
    extern "C" {
    #endif
    // Define a dummy function; if A is not present we will make A an alias of this
    int A_surrogate() {}
    #ifdef __cplusplus
    }
    #endif
    
    // The alias attribute makes 'A' equivalent to 'A_surrogate'. The weak attribute
    // means that if some other definition exists, that one takes precedence.
    int __attribute__((weak, alias("A_surrogate"))) A();
    
    int is_A_present() {
      // Was A in fact overridden?
      return &A != &A_surrogate;
    }
    

    【讨论】:

    • 非常感谢 Linux 解决方案的提示,但在我的情况下不会这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 2014-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    • 2014-11-26
    相关资源
    最近更新 更多