如何测试是否定义了只能通过#define 宏访问的标识符?

How to test whether an identifier that is accessible only through a #define macro is defined?

我有一个 #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" 的标识符的东西。解决方案必须与平台无关。

抱歉,如果之前有人问过这个问题,我找不到,google 和 SO 都找不到。

定义标识符(函数、对象)是在预处理之后发生的事情,因此您无法在预处理期间确定稍后是否定义函数。

你可以做的解决方法是你总是定义一个宏和函数:

void A();
#define A_SUPPLIED

然后进行测试:

#ifdef A_SUPPLIED
...
#endif

嗯,没有。

我认为你真正的问题是你不理解宏之间的区别(使用 #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

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

但是,如果这不是一个选项,则可以使用 platform-specific 扩展。例如在Linux上,你可以定义一个weak symbol,然后判断它是否被real deal覆盖:

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