如何消除冗余宏参数

不久前,我为一个大型项目编写了一组X-macro。我需要维护字符串和枚举引用/哈希值/回调函数等的连贯列表。这是函数回调的样子
#define LREF_LOOKUP_TABLE_TEXT_SIZE 32
#define _LREF_ENUM_LIST(_prefix,_ref,...) _prefix ## _ ## _ref,
#define _LREF_BASE_STRUCT_ENTRY(_prefix,_ref) .text= #_ref "", .position= _LREF_ENUM_LIST(_prefix, _ref)
#define _LREF_FUNCTION_STRUCT_LIST(_prefix,_ref,...) {_LREF_BASE_STRUCT_ENTRY(_prefix,_ref) _prefix ## _ ## _ref ## _callback},

#define _LREF_ENUM_TYPEDEF(_prefix)                                                
    typedef enum _prefix                                                            
    {                                                                               
        _ ## _prefix ## s(_prefix,_LREF_ENUM_LIST)                                 
        _LREF_ENUM_LIST(_prefix,tblEnd)                                            
    } e_ ## _prefix

#define _LREF_LOOKUP_TABLE_TYPEDEF(_prefix, _extras)                               
    typedef struct _prefix ## _lookup                                              
    {                                                                              
        const char text[LREF_LOOKUP_TABLE_TEXT_SIZE];                              
        e_ ## _prefix position;                                                    
        _extras                                                                    
    } _prefix ##_lookup_t

#define LREF_GENERIC_LOOKUP_TABLE(_prefix, _type, _tabledef, _listdef, _extras)    
    _LREF_ENUM_TYPEDEF(_prefix);                                                   
    _LREF_LOOKUP_TABLE_TYPEDEF(_prefix,_tabledef);                                 
    _extras                                                                        
    _LREF_LOOKUP_TABLE_DECLARATION(_prefix,_listdef, _type)

#define LREF_FUNCTION_LOOKUP_TABLE(_prefix, _type)                                 
    _ ## _prefix ## s(_prefix, _LREF_FUNCTION_DEF )                                
    LREF_GENERIC_LOOKUP_TABLE(    _prefix,                                         
        _type,                                                                     
        void* (*function) (void*);,                                                
    _LREF_FUNCTION_STRUCT_LIST,  )
它位于头文件中,允许我编写如下内容:
#define _cl_tags(x,_)         
    _(x, command_list)        
    _(x, command)             
    _(x, parameter)           
    _(x, fixed_parameter)     
    _(x, parameter_group)     
    _(x, group)                
    _(x, map)                 
    _(x, transform)

LREF_FUNCTION_LOOKUP_TABLE(cl_tag, static);
这使处理程序变得简短。例如,使用上述标签加载配置文件只需:
for (node_tag = cl_tag_lookup_table; node_tag->position != cl_tag_tblEnd; node_tag++)
{
    if (strcasecmp(test_string, node_tag->text) == 0)
    {
        func_return = node_tag->function((void*)m_parser);
    }
}
我的问题是:我讨厌我必须在我的
#define
中包含第二个参数。我希望能够写
#define _cl_tags(_)
而不是
#define _cl_tags(x,_)
。如您所见,
x
仅用于传递前缀(cl_tag)。但这是多余的,因为前缀是初始宏的参数。 如果我的预处理器首先扩展最外层的宏,那么解决这个问题会很容易。不幸的是,GCC的预处理器在扩展最外层宏之前通过最内层的宏(即参数值)工作。 我正在使用gcc 4.4.5 澄清 按C89(和C99)标准,定义如下
#define plus(x,y) add(y,x)
#define add(x,y) ((x)+(y))
随着调用
plus(plus(a,b),c)
应该屈服
plus(plus(a,b),c)
add(c,plus(a,b))
((c)+(plus(a,b))
((c)+(add(b,a))
((c)+(((b)+(a))))
gcc 4.4.5给出
plus(plus(a,b),c)
plus(add(b,a),c)
plus(((b)+(a)),c)
add(c,((b)+(a)))
((c)+(((b)+(a))))
    
已邀请:
这就是我要做的事情(做得类似): 将它们放在实用程序头文件中:
/*
 * Concatenate preprocessor tokens A and B without expanding macro definitions
 * (however, if invoked from a macro, macro arguments are expanded).
 */
#define PPCAT_NX(A, B) A ## B

/*
 * Concatenate preprocessor tokens A and B after macro-expanding them.
 */
#define PPCAT(A, B) PPCAT_NX(A, B)
然后在包含LREF宏头文件之前定义它:
#define LREF_TAG cl_tag
然后,在您的LREF宏头文件中,
#define LREF_PFX(x) PPCAT(LREF_TAG, x)
#define LREF_SFX(x) PPCAT(x, LREF_TAG)
然后用
LREF_PFX(foo)
替换
_prefix ## foo
的每个实例,用
LREF_SFX(foo)
替换
foo ## _prefix
。 (当将两个以上的令牌粘贴在一起时,只需使用嵌套的PPCAT。) 你的调用会变成
#define LREF_TAG cl_tag
#define _cl_tags(_)        
    _(command_list)        
    _(command)             
    _(parameter)           
    _(fixed_parameter)     
    _(parameter_group)     
    _(group)                
    _(map)                 
    _(transform)

LREF_FUNCTION_LOOKUP_TABLE(static);
    
这个答案只是解决'澄清'。这是正确的行为:
#define plus(x,y) add(y,x)
#define add(x,y) ((x)+(y))

Initial:   plus(plus(a,b),c)
Pass 1a:   plus(add(b,a),c)
Pass 1b:   add(c,add(b,a))
Pass 2a:   add(c,((b)+(a)))
Pass 2b:   ((c)+(((b)+(a))))
规则是每个宏一次非递归地替换(从嵌入时的最内层开始);然后一个新的传递(又称“重新扫描”)发生重复相同的过程,这一直持续到传递不执行任何替换。 我不确定你要做的是什么,因为你给GCC和你期望发生的事情给出了相同的最终结论。     

要回复问题请先登录注册