C "#define"函数名称生成



我有concrete_impl.h (as is):

#ifdef TUPLE_ITERATOR_WITH_INDEX
    #define TUPLE_ITERATOR TUPLE_ITERATOR_NO_INDEX
    #define iterate_tuple_fname iterate_tuple_id
#else
    #define TUPLE_ITERATOR TUPLE_ITERATOR_INDEX
    #define iterate_tuple_fname iterate_tuple
#endif
#undef  iterate_tuple_fname_back
#define iterate_tuple_fname_back iterate_tuple_fname##_back
static void iterate_tuple_fname()         // ok 
{
}
static void iterate_tuple_fname_back()   // redefinition error
{
}

concrete.h(原样):

#ifndef CONCRETE_H
#define CONCRETE_H
#define TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"
#undef TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"

#endif // CONCRETE_H

我想要得到的是4个函数:

  • iterate_tuple
  • iterate_tuple_id
  • iterate_tuple_back
  • iterate_tuple_id_back

但是在"_back"函数上,我有重定义错误。为什么?

iterate_tuple_fname##_back就是iterate_tuple_fname_back。要用它的宏替换列表替换iterate_tuple_fname,您需要一个helper宏:

#define CONCAT(a, b) a ## b
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)

更新:对不起,在c#编程几年之后,我已经把C忘得一干二净了。

实际上需要double通过helper宏运行:

#define CONCAT1(a, b) a ## b
#define CONCAT(a, b) CONCAT1(a, b)
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)

显然你误解了##操作符的工作方式。

  • 如果##操作符旁边的预处理令牌是当前宏的参数,则对该参数进行递归分析以进一步替换首先,并将该替换的结果替换到结果中。

  • 如果##操作符旁边的预处理令牌是而不是当前宏的参数,则不会进行该令牌的递归分析和替换。令牌与另一个令牌简单地连接在一起。

之后,一旦替换了所有参数并连接了所有连接,将再次重新扫描整个结果以进行进一步替换。但是对于你的榜样来说已经太迟了。

在您的例子中,您定义了这个宏
#define iterate_tuple_fname_back iterate_tuple_fname##_back

由于iterate_tuple_fname不是这个宏的参数,因此不会提前替换iterate_tuple_fname。整个内容立即连接到iterate_tuple_fname_back中,然后重新扫描。但是重新扫描没有发现任何可替换的,所以iterate_tuple_fname_back是最终结果。

如果您希望预处理器替换##操作符的左侧(这显然是您的意图),则绝对必须在左侧使用宏参数,如

#define ITF_back(prefix) prefix##_back

,然后你可以使用这个宏作为

ITF_back(iterate_tuple_fname)

现在iterate_tuple_fname内部的重新扫描和递归替换将提前发生,在与_back部分连接之前。也就是说,它会像你想要的那样工作。

最新更新