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

时间:2015-06-21 07:46:22

标签: c++ c macros

我有#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。

3 个答案:

答案 0 :(得分:2)

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

您可以做的解决方法是始终使用函数定义宏:

void A();
#define A_SUPPLIED

然后对此进行测试:

#ifdef A_SUPPLIED
...
#endif

答案 1 :(得分:1)

嗯,不。

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

答案 2 :(得分:1)

无论是否存在宏,您都无法确定纯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;
}