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

Creating a function in compile time using a bitmap like macro

我有一个 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 结构来实现吗?因为我试图保留所有内容,所以我不想编写脚本来为我生成代码。我需要的是使用位图宏之类的东西指定模式,而不是在编译时生成函数。

我的方法是使用一个定义了所有你想要的模式的宏,结合其他定义函数或你需要的关于它们的信息的宏。所以你会有这样的东西:

#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

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

FUNCTION_PATTERNS(DEFINE_SUM_FUNCTION)

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

如果需要,您可以在 DEFINE_SUM_FUNCTION 宏中手动展开循环,或者您可以依靠您的 C 编译器为您完成,可能需要适当的 pragma 或编译时标志。

请注意,以上内容最多只能处理 32 或 64 个元素(取决于架构)。如果您想要更多,则必须将模式拆分为多个值。

扩展 Chris Dodd 的方法。

我认为您可以通过使用模式符号列表来准确生成您所描述的内容。因此,从相同的 X 宏设置开始。

#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 后记。 :)