使用像宏这样的位图在编译时创建函数

时间:2015-06-22 00:02:12

标签: c macros

我有一个ansi C函数,可以根据模式对数组中的值求和。类似的东西:

long sum_all_according_to_pattern(int n, int *values, int *pattern)
{
    long sum = 0;
    int i = 0;
    for(;i<n;i++){
        if(pattern[i])
            sum+=values[i];
    }
    return sum;
}

我们说我有一套模式,例如:

模式1:1,1,1,1

模式2:1,1,0,0

模式3:1,0,0,1

我需要为每个模式生成一个特定的代码,没有循环和if。对于以前的模式,它将是:

long sum_according_to_pattern_1(int *values)
{
    return values[0]+values[1]+values[2]+values[3];
}

long sum_according_to_pattern_2(int *values)
{
    return values[0]+values[1];
}

long sum_according_to_pattern_3(int *values)
{
    return values[0]+values[3];
}

甚至

long sum_according_to_pattern_1(int *values)
{
    long sum = 0;
    sum+=values[0];
    sum+=values[1];
    sum+=values[2];
    sum+=values[3];
    return sum;
}

long sum_according_to_pattern_2(int *values)
{
    long sum = 0;
    sum+=values[0];
    sum+=values[1];
    return sum;
}

long sum_according_to_pattern_3(int *values)
{
    long sum = 0;
    sum+=values[0];
    sum+=values[3];
    return sum;
}

现在,假设这样的模式可以比仅仅4个元素大得多。另外,假设我不仅仅是这3种模式。

我的问题是:有一些方法可以使用ansi C构造实现这一目标吗?当我试图保持所有内容时,我不想编写脚本来为我生成代码。我需要的是使用类似位图宏的方式指定模式,然后在编译期间生成函数。

2 个答案:

答案 0 :(得分:2)

我会这样做的方法是使用一个宏来定义你想要的所有模式,并结合其他宏来定义你需要的函数或其他信息。所以你会有类似的东西:

#define FUNCTION_PATTERNS(M) \
    M(1, 0xf) \
    M(2, 0x3) \
    M(3, 0x9)

#define DEFINE_SUM_FUNCTION(NUM, PATTERN) \
long sum_according_to_pattern_##NUM(int *values) {   \
    long sum = 0;                                    \
    for (int i = 0; 1UL << i <= PATTERN; i++)        \
        if (PATTERN & (1UL << i)) sum += values[i];  \
}

#define SUM_FUNCTION_NAME(NUM, PATTERN) sum_according_to_pattern_##NUM

现在您可以轻松声明所有函数并构建一个指向它们的指针表:

FUNCTION_PATTERNS(DEFINE_SUM_FUNCTION)

long (*sum_functions[])(int *) = { FUNCTION_PATTERNS(SUM_FUNCTION_NAME) };

如果需要,可以在DEFINE_SUM_FUNCTION宏中手动展开循环,或者依靠C编译器为您执行此操作,可能使用适当的编译指示或编译时标志。

请注意,上述内容最多只能使用32或64个元素(具体取决于体系结构)。如果你想要更多,你必须将模式分成多个值。

答案 1 :(得分:0)

扩展Chris Dodd的方法。

我认为您可以使用模式的符号列表生成您描述的内容。所以,从相同的X-macro设置开始。

#define PATTERNS(_) \
_(1, A B C D) \
_(2, A B) \
_(3, A D) \
/**/

#define A sum += values[0];
#define B sum += values[1];
#define C sum += values[2];
#define D sum += values[3];
#define GEN_FUNC(num, pattern) \
long sum_accoring_to_pattern ## num (int *values) { \
    long sum = 0; \
    pattern \
    return sum; \
}

PATTERNS(GEN_FUNC)

贯穿cpp -P genpat.c | indent -gnu -i4 -br -ce -cdw -nbc -brf -brs -l100 -bbo收益

long
sum_accoring_to_pattern1 (int *values) {
    long sum = 0;
    sum += values[0];
    sum += values[1];
    sum += values[2];
    sum += values[3];
    return sum;
}

long
sum_accoring_to_pattern2 (int *values) {
    long sum = 0;
    sum += values[0];
    sum += values[1];
    return sum;
}

long
sum_accoring_to_pattern3 (int *values) {
    long sum = 0;
    sum += values[0];
    sum += values[3];
    return sum;
}

您还可以生成较短的表单。

#define PATTERNS(_) \
_(1, A B C D) \
_(2, A B) \
_(3, A D) \
/**/

#define A + values[0]
#define B + values[1]
#define C + values[2]
#define D + values[3]
#define GEN_FUNC(num, pattern) \
long sum_accoring_to_pattern ## num (int *values) { \
    return pattern ;\
}

PATTERNS(GEN_FUNC)

您几乎肯定希望#undef A .. D后记。 :)