【问题标题】:Is there any way to split gcc macro arguments?有没有办法拆分 gcc 宏参数?
【发布时间】:2013-01-16 07:39:46
【问题描述】:

我编写的代码可以在 GPU 或 CPU 上运行。如果存在 CUDA 存在包装器,请尝试在 GPU 上运行函数。如果出现错误(例如没有内存),它会尝试在 CPU 上运行它。如果再次出错则返回 0,否则返回 1。 如果 CUDA 缺少包装器,则仅尝试在 CPU 上运行函数。

这是我的宏:

#ifdef CUDA_FOUND
#define SET_F(FNARGS, FNSTRIP) int FNARGS{  \
    if(!Only_CPU) if(CU ## FNSTRIP) return 1;\
    if(CPU ## FNSTRIP) return 1;            \
    return 0;                               \
}
#else
#define SET_F(FNARGS, FNSTRIP) int FNARGS{  \
    if(CPU ## FNSTRIP) return 1;            \
    return 0;                               \
}
#endif // CUDA_FOUND

为了定义新函数,我这样称呼它:

SET_F(fillrandarr(size_t sz, char *arr), fillrandarr(sz, arr))

问题:有没有办法将FNARGS 的这个宏拆分参数简化为组合FNSTRIP? IE。将上面的定义缩短为

SET_F(fillrandarr(size_t sz, char *arr))

?

【问题讨论】:

  • 我希望您会将此宏用于更多功能,而不是您发布的功能。它们都只有两个参数吗?
  • 会有很多函数,它们的参数数量因一个函数而异。它们唯一的共同点是它们返回int。
  • Boost 预处理器库可能可以做到这一点。
  • “Boost 预处理器库”?在 C 中?
  • Boost 通常是 C++,但预处理器库只是一组宏,没有(据我所知)C++ 特定的部分。

标签: c gcc macros


【解决方案1】:

作为 n.m.在他的 cmets 中写道:

Boost 预处理器库可能可以做到这一点。
Boost 通常是 C++,但预处理器库只是一组宏,没有(据我所知)C++ 特定的部分。

所以这是一个提升的解决方案:

#define BOOST_PP_VARIADICS 1

#include <boost/preprocessor.hpp>

#define FOO(...) FOO2(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define FOO2(seq) FOO3(BOOST_PP_SEQ_HEAD(seq),BOOST_PP_SEQ_TAIL(seq))
#define FOO3(name, args) FOO6(name,                                \
                              BOOST_PP_SEQ_FOR_EACH_I(FOO4,,args), \
                              BOOST_PP_SEQ_FOR_EACH_I(FOO5,,args))
#define FOO4(rep, data, index, type) (type BOOST_PP_CAT(arg,index))
#define FOO5(rep, data, index, type) (BOOST_PP_CAT(arg,index))
#define FOO6(name, dargs, cargs)                                   \
  FOO8(name, FOO7(dargs, void), FOO7(cargs, ))
#define FOO7(seq, empty)                                           \
  BOOST_PP_IF(BOOST_PP_SEQ_SIZE(seq),                              \
              BOOST_PP_SEQ_TO_TUPLE(seq), (empty))
#define FOO8(name, dargs, cargs)                                   \
  int name dargs {                                                 \
    if (BOOST_PP_CAT(CPU_, name)cargs)                             \
      return 1;                                                    \
    return 0;                                                      \
  }

FOO(fillrandarr, size_t, char*)
FOO(fun1, int, double)
FOO(fun2)

它生成这样的代码(格式由我添加):

int fillrandarr (size_t arg0, char* arg1) {
  if (CPU_fillrandarr(arg0, arg1))
    return 1;
  return 0;
}

int fun1 (int arg0, double arg1) {
  if (CPU_fun1(arg0, arg1))
    return 1;
  return 0;
}

int fun2 (void) {
  if (CPU_fun2())
    return 1;
  return 0;
}

我省略了宏调用中的参数名称,因为它们实际上并不重要。已特别注意处理最后一种情况,即在同一框架中正确处理没有参数的函数。

以下是不同的步骤:

  1. 由于可变参数宏显然无法区分零参数和单个空参数,因此第一个始终包含函数名称的宏必须将可变参数转换为更易于处理的数据结构,在这种情况下是一系列带括号的表达式。
  2. 接下来,我们将该序列拆分为函数名称和参数类型。
  3. 我们将参数类型序列转换为两个序列,一个用于函数定义,另一个用于函数调用。
  4. 对于函数定义,我们在每个参数名称前加上其类型。
  5. 对于函数调用,我们忽略类型,只写带编号的参数名称。
  6. 接下来我们必须确保正确处理空序列。对于调用,我们可以简单地写成(),但对于函数定义,我们必须写成(void)。
  7. 因此我们检查序列是否具有非零大小。如果是这样,我们将其转换为元组,即元素之间的逗号和括号。否则我们使用提供的默认值。
  8. 现在我们按照您要求的方式组合所有内容。

【讨论】:

  • 这很有趣。但我有几个问题:1)这是否适用于 gcc-none-eaby? 2) 是否有关于 boost 预处理器指令的简短手册?
  • @Eddy_Em:我不知道你所说的“gcc-none-eaby”是什么意思。请解释一下。一般来说,boost 已针对各种常见编译器的可移植性进行了高度调整,并且标头包含许多大小写区别,以解决编译器特定的奇怪问题。因此,使用 boost 可能比直接实现更便携。例如,参见variadic argument counting 中 MSVC 的特殊情况。有关手册,请参阅the docs,尤其是那里的参考资料。
  • 我的意思是非 x86 处理器的编译器。
  • @Eddy_Em,处理器架构应该与预处理器几乎无关,所以我认为那里没有问题。上面的代码使用可变参数宏,如果这些宏不可用,您必须更改前几个宏以及调用顶部宏的方式,例如到FOO(2,fun1,(int,double))。但是大多数编译器应该能够使用可变参数宏。在我的 boost 版本中,支持的参数数量似乎是 64,包括函数名称。
【解决方案2】:

您可以为使用不同数量参数的函数声明包装宏:

#define SET_F_2(fname, \
  vtype1, vname1, \
  vtype2, vname2 \
) \
  SET_F( \
    fname( \
      vtype1 vname1, \
      vtype2 vname2 \
    ), \
    fname( \
      vname1, \
      vname2 \
    ) \
)

#define SET_F_3(fname, \
  vtype1, vname1, \
  vtype2, vname2, \
  vtype3, vname3 \
) \
  SET_F( \
    fname( \
      vtype1 vname1, \
      vtype2 vname2, \
      vtype3 vname3 \
    ), \
    fname( \
      vname1, \
      vname2, \
      vname3 \
    ) \
)

... and so on

像这样使用它:

SET_F_2(x, short, s, int, i);
SET_F_3(y, int, i, short, s, float, f);

使用slartibartfast proposal 计算#define 的参数数量,这种方法肯定会针对更少的冗余进行优化。

【讨论】:

  • 这是一个非常庞大的结构。还有一些我的函数有多达 5-7 个参数!但是想法很好。谢谢你。顺便说一句,在宏 SET_F_X 中写变量名是没有用的:它们可以自己设置。
【解决方案3】:

你不能用预处理器拆开预处理符号,你只能将它们组合起来。这意味着“fillrandarr(sz,arr)”是预处理器的一个原子单元,因此不适合您的需要。您必须传递在参数列表中分隔的符号,例如

#define SET_F(f_name,p1_type,p1_name,p2_type,p2_name) ...

对于进入函数的可变数量的参数使用

#define CNT_ARGS(...) CNT_ARGS_(__VA_ARGS__,8,7,6,5,4,3,2,1)
#define CNT_ARGS_(_1,_2,_3,_4,_5,_6,_7,_8,n) n

#define DROP_TYPE(...) DROP_TYPE_(CNT_ARGS(__VA_ARGS__),__VA_ARGS__)
#define DROP_TYPE_(n,...) DROP_TYPE__(n,__VA_ARGS__)
#define DROP_TYPE__(n,...) DROP_TYPE_##n(__VA_ARGS__)
#define DROP_TYPE_2(ptype,pname,...) pname
#define DROP_TYPE_4(ptype,pname,...) pname, DROP_TYPE_2(__VA_ARGS__)
#define DROP_TYPE_6(ptype,pname,...) pname, DROP_TYPE_4(__VA_ARGS__)
#define DROP_TYPE_8(ptype,pname,...) pname, DROP_TYPE_6(__VA_ARGS__)


#define FOO(fname,...)  fname(DROP_TYPE(__VA_ARGS__))

    FOO(my_func,t1,p1,t2,p2,t3,p3,t4,p4)  -> my_func(p1,p2,p3,p4)
    FOO(other_func,t1,p1,t2,p2)           -> other_func(p1,p2)

【讨论】:

  • 呵呵,这是第1步,你确定剩下的步骤都可以吗?
  • 我想过,但我想不出如何解析变量参数,以便在一种情况下它们是成对的组,而在另一种情况下只有奇数组。
【解决方案4】:

毕竟我做了接下来的事情(最多 10 个参数):

#define Fn1(A,B) A(x1)
#define Df1(A,B) A(B x1)
#define Fn2(A,B,C) A(x1, x2)
#define Df2(A,B,C) A(B x1, C x2)
#define Fn3(A,B,C,D) A(x1, x2, x3)
#define Df3(A,B,C,D) A(B x1, C x2, D x3)
#define Fn4(A,B,C,D,E) A(x1, x2, x3, x4)
#define Df4(A,B,C,D,E) A(B x1, C x2, D x3, E x4)
#define Fn5(A,B,C,D,E,F) A(x1, x2, x3, x4, x5)
#define Df5(A,B,C,D,E,F) A(B x1, C x2, D x3, E x4, F x5)
#define Fn6(A,B,C,D,E,F,G) A(x1, x2, x3, x4, x5, x6)
#define Df6(A,B,C,D,E,F,G) A(B x1, C x2, D x3, E x4, F x5, G x6)
#define Fn7(A,B,C,D,E,F,G,H) A(x1, x2, x3, x4, x5, x6, x7)
#define Df7(A,B,C,D,E,F,G,H) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7)
#define Fn8(A,B,C,D,E,F,G,H,I) A(x1, x2, x3, x4, x5, x6, x7, x8)
#define Df8(A,B,C,D,E,F,G,H,I) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7, I x8)
#define Fn9(A,B,C,D,E,F,G,H,I,J) A(x1, x2, x3, x4, x5, x6, x7, x8, x9)
#define Df9(A,B,C,D,E,F,G,H,I,J) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7, I x8, J x9)
#define Fn10(A,B,C,D,E,F,G,H,I,J,K) A(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)
#define Df10(A,B,C,D,E,F,G,H,I,J,K) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7, I x8, J x9, K x10)

#define DEF(N, ...) int Df ## N(__VA_ARGS__)
#define CONCAT(A, B) A ## B
#define FN(N, ...) Fn ## N(__VA_ARGS__)
#define DF(N, ...) Df ## N(__VA_ARGS__)
#define XFUNC(T, X) CONCAT(T, X)
#define FUNC(T, ...) XFUNC(T, FN(__VA_ARGS__))
#define DFUNC(T,...) EXTERN int XFUNC(T, DF(__VA_ARGS__))

#ifdef WRAPPER_C
// even when using cuda in case of fail CUDA init use CPU
static int Only_CPU =
#ifdef CUDA_FOUND
    0
#else
    1
#endif
;
#ifdef CUDA_FOUND
#define SET_F(...) DEF(__VA_ARGS__){                    \
    if(!Only_CPU) if(FUNC(CU, __VA_ARGS__)) return 1;   \
    if(FUNC(CPU, __VA_ARGS__)) return 1;                \
    return 0;                                           \
}
#else
#define SET_F(...) DEF(__VA_ARGS__){                    \
    if(FUNC(CPU, __VA_ARGS__)) return 1;                \
    return 0;                                           \
}
#endif // CUDA_FOUND
#else
    #define SET_F(...)
#endif // WRAPPER_C

#ifdef CPU_C // file included from CPU.c
    #define BOTH(...) DFUNC(CPU, __VA_ARGS__);
    //#pragma message "CPUC"
#elif defined CUDA_CU //file included from CUDA.cu
    #define BOTH(...) DFUNC(CU, __VA_ARGS__);
#elif defined WRAPPER_C // wrapper.c needs names of both wariants
    #ifndef CUDA_FOUND
        #define BOTH(...) DFUNC(CPU, __VA_ARGS__);
    #else
        #define BOTH(...) DFUNC(CU, __VA_ARGS__); DFUNC(CPU, __VA_ARGS__);
    #endif // CUDA_FOUND
#else // file included from something else - just define a function
    #define BOTH(...) DFUNC(, __VA_ARGS__);
#endif

#define DFN(...) BOTH(__VA_ARGS__) SET_F(__VA_ARGS__)

此代码在文件 wrapper.h 中。 wrapper.c 只包含代码的公共部分。

要定义我在 wrapper.h 中编写的函数,例如:

DFN(2, fillrandarr, size_t, float *)
DFN(6, bicubic_interp, float *, float *, size_t, size_t, size_t, size_t)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-09
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    相关资源
    最近更新 更多