3

假设我的代码如下所示:

#ifdef COND1
    extern int func1(void);
#endif
...
#ifdef CONDN
    extern int funcn(void);
#endif

my_struct funcs[] = {
#ifdef COND1
    {"func1 description", func1},
#endif
...
#ifdef CONDN
    {"funcn description", funcn},
#endif
    {NULL, NULL},
};

是否可以用X 宏替换它,以尽量减少两个部分中函数名称和条件的重复?

如果没有#ifdef CONDX条件,这似乎很简单。但是,我不知道如何将它们包含在 X 宏中,因为它不允许#ifdef#define.

4

5 回答 5

0

不确定X 宏是否是这里的解决方案。但是,您可以使用一些预处理器魔法来减少输入。问题仍然是您示例中的条件编译(#ifdefs)。如果不知道这些条件是什么样的,就很难进一步减少打字量。

考虑以下情况:

#define D(n) extern int func ## n(void);
#define A(n) {"func" #n " description", func ## n},

#ifdef COND1
  D(1)
#endif
#ifdef COND2
  D(2)
#endif

my_struct funcs[] = {
#ifdef COND1
  A(1)
#endif
#ifdef COND2
  A(2)
#endif
};

我认为,这是朝着您的目标方向迈出的一步。要查看它的作用,您可以尝试

gcc -E -DCOND1 <file-with-contents-above>.c

(如果你在某些 Unix 上)或

cl -E -DCOND1 <file-with-contents-above>.c

(如果您在 Windows 上使用 Visual Studio)。

于 2015-06-04T12:14:54.673 回答
0

假设您要定义 COND1 但没有 CONDN。我认为您可以执行以下操作:

#define COND1(...) __VA_ARGS__
#define CONDN(...)

#define MY_XLIST \
    X(COND1, func1, "func1 description") \
    X(CONDN, funcn, "funcn description")

#define X(a, b, c) a(extern int b (void);)
MY_XLIST
#undef X

#define X(a, b, c) a({c, b},)
my_struct funcs[] = {
    MY_XLIST
    {NULL, NULL},
};
#undef X

问题是你需要定义所有的宏,但是有不同的扩展。

于 2015-06-04T12:25:49.483 回答
0

你不能使用#ifdefinside #define,所以你不能使用#define基于 X 宏,但你仍然可以使用#include基于 X 宏。

例如,使用一个文件t.def

#ifdef COND1
F(func1, "func1 description")
#endif
#ifdef COND2
F(func2, "func2 description")
#endif

在您的主文件中:

#define COND2

#define F(name, desc) extern int name(void);
#include "t.def"
#undef F

mystruct funcs[] = {
    #define F(name, desc) {desc, name},
    #include "t.def"
    #undef F
    {NULL, NULL},
};

这将被处理为:

extern int func2(void);

mystruct funcs[] = {
    {"func2 description", func2},
    {NULL, NULL},
};
于 2015-06-04T12:27:54.403 回答
0

我认为,关键是要“排除”这种情况。例如,COND1(或 COND2 等)应该围绕funcs数组的定义,反之亦然。在这里,我假设您可以将条件归结为整数定义。这可以通过例如

#if COND1
#   define N 1
#elif COND2
#   define N 2
// ...
#endif

我们还假设您有几个函数存根(不仅是func),它们都扩展为stub<n>类似名称。然后您可以完全参数化您的函数名称生成,如下所示。(代码使用字符串文字连接和for 循环变量。gcc -std=c99编译得很好。)

主文件。声明函数并定义描述结构数组。

#include<stdio.h>

// example struct definition
typedef struct { const char* description; int (*f)(void); } my_struct;

// A two-stage macro expansion is necessary because
// macro parameters are taken literally when used in 
// concatenation or stringification 
// (cf. https://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html)

// Expands to function declaration
#define X_LITERAL_PARAMS(fname, suffix) extern int fname ## suffix (void);
#define X(fname, suffix) X_LITERAL_PARAMS(fname, suffix) // this expands suffix e.g. to 1 

// define extern int functions
#define N 1 // select which function variants
#include "xmacro_x.h"   

#undef X_LITERAL_PARAMS
#define X_LITERAL_PARAMS(fname, suffix) { "Calling " #fname #suffix, fname ## suffix},

my_struct funcs[] = {
#undef N
#define N 1 // select which function variants
#include "xmacro_x.h"   
//  defines descriptions for functions
#   include "xmacro_x.h"    

};

// Print description and call each function 
// in the struct array 
int main(void)
{
    for(int i=0; i<sizeof(funcs)/sizeof(my_struct); i++)
    {
        printf("%s yields %d\n\n", funcs[i].description, funcs[i].f());
    }

    return 0;
}

文件 funcs.c 实际上定义了函数。

// Define functions named as in the struct array
// for proof of concept

#include <stdio.h>

// two-stage expansion again 
#define  X_LITERAL_PARAMS(f, n) \
    int f ## n (void){ return printf("This is %s\n", #f #n);}

#define X(a,b) X_LITERAL_PARAMS(a,b)

#define N 1
#include "xmacro_x.h"

最后,相当无趣的文件 xmacro_x.h 提供了扩展为源文件中不同代码片段的“X 宏”。这里介绍了各种“函数族”,名称存根,稍后将与数字后缀组合。

// The "X macros" which will be expanded to different things later
X(func, N)
X(gunc, N)
//...
于 2015-06-04T13:16:39.197 回答
0

使用 x 宏(我称它们为列表宏)进行条件编译的关键是要了解预处理器指令不能包含在宏中,但列表宏可以从较小的列表中拼凑起来。然后,较小列表的输出可以是有条件的。

解决方案位于下面代码的开头,但为了完整起见,我添加了列表宏的输出。另外,请注意,较小的列表是一个项目的列表,但它们可以很容易地包含多个项目。

//Inner macro parameter list.
//FUNC_(enumTag, function, description)

//Conditional sublist.
#ifdef COND1
#define COND1_FUNC_LIST \
    FUNC_(FuncCOND_1, func1, “func1 description”)
#else
#define COND1_FUNC_LIST
#endif

//Conditional sublist.
#ifdef CONDN
#define CONDN_FUNC_LIST \
    FUNC_(FuncCOND_N, funcn, “funcn description”)
#else
#define CONDN_FUNC_LIST
#endif

//Complete list.
#define FUNC_LIST \
    COND1_FUNC_LIST \
    CONDN_FUNC_LIST \
//Comment to terminate preprocessor continuation.


//The rest generates all of the code artifacts.
#define CONDN_FUNC_ENUM(enumTag, function, description) enumTag,
#define CONDN_FUNC_EXTERN(enumTag, function, description) extern int function(void);
#define CONDN_FUNC_INITIALIZER(enumTag, function, description) {function, description},

typedef int (*FuncPtr)(void);
typedef struct
{
    FuncPtr function;
    char * description;
} FuncStruct;

enum
{
    FUNC_LIST(CONDN_FUNC_ENUM)
    FuncCOUNT
};

FUNC_LIST(CONDN_FUNC_EXTERN)

FuncStruct funcs[FuncCOUNT] = 
{
    FUNC_LIST(CONDN_FUNC_INITIALIZER)
};
于 2017-04-25T15:47:56.710 回答