C 宏到按位 OR,将可变数量的参数放在一起(不带 P99 的轻量级解决方案)

C macro to bitwise-OR together a variable number of arguments (lightweight solution without P99)

提问人:swineone 提问时间:10/6/2023 更新时间:10/7/2023 访问量:145

问:

我需要一个按位 ORs 将其(可变数量的)参数组合在一起的宏:

int main() {
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4));
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4, 8, 16));
}

这应该打印:

7
31

我有一个使用 P99 的解决方案:

#include "p99/p99_for.h"

#define P00_IDT(NAME, X, I) X
 
#define BITWISE_OR_MULTIPLE_ARGS(...) P99_FOR(A, P99_NARG(__VA_ARGS__), P00_BOR, P00_IDT, __VA_ARGS__)

但是,这是我的代码库中 P99 的唯一用途,我发现导入所有 P99 有点重量级。如何使用一组独立的宏来实现这一点?

C-预处理器

评论

0赞 Some programmer dude 10/6/2023
也许将您需要的宏从这个“P99”库复制到您自己的代码中?
0赞 swineone 10/6/2023
@Someprogrammerdude 这是一种可能性,但恐怕它可能需要复制数百行代码,因为库是通用的。我怀疑最多可以用 10 或 20 行代码来解决。
5赞 dbush 10/6/2023
似乎只按位执行 OR 会更简单。
1赞 Ian Abbott 10/6/2023
你为什么需要这个?是要处理一些外部生成的逗号分隔值源还是其他什么?
1赞 Ian Abbott 10/6/2023
如果您确实使用 P99,它已经有一个宏。P99_BORS(...)

答:

1赞 nielsen 10/6/2023 #1

您可以使用此答案中的方法。

例如,最多有 5 个参数:

#include <stdio.h>

#define BOR2(a,b) ((a) | (b))
#define BOR3(a,b,c) (BOR2(a,b) | (c))
#define BOR4(a,b,c,d) (BOR3(a,b,c) | (d))
#define BOR5(a,b,c,d,e) (BOR4(a,b,c,d) | (e))

#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME
#define BITWISE_OR_MULTIPLE_ARGS(...) GET_MACRO(__VA_ARGS__, BOR5, BOR4, BOR3, BOR2)(__VA_ARGS__)

int main()
{
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4));
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4, 8, 16));

    return 0;
}

评论

0赞 swineone 10/6/2023
这是一个很好的开始。但是,我正在使用大型位域(带有 64 位变量),因此我可能需要多达 64 个参数——我不太可能使用所有这些参数,但肯定超过 5 个。我想我在某处看到了一个技巧,所以你可以只构建对数数量的宏,等?BOR2BOR3
3赞 Michael Walsh Pedersen 10/6/2023 #2

您可以使用 2 个宏来完成:

#define A(a0,a1,a2,a3,a4,a5,a6,a7,b0,b1,b2,b3,b4,b5,b6,b7,\
 c0,c1,c2,c3,c4,c5,c6,c7,d0,d1,d2,d3,d4,d5,d6,d7,e0,e1,e2,e3,e4,e5,e6,e7,\
 f0,f1,f2,f3,f4,f5,f6,f7,g0,g1,g2,g3,g4,g5,g6,g7,h0,h1,h2,h3,h4,h5,h6,h7,...)\
 a0|a1|a2|a3|a4|a5|a6|a7|b0|b1|b2|b3|b4|b5|b6|b7|c0|c1|c2|c3|c4|c5|c6|c7|\
 d0|d1|d2|d3|d4|d5|d6|d7|e0|e1|e2|e3|e4|e5|e6|e7|f0|f1|f2|f3|f4|f5|f6|f7|\
 g0|g1|g2|g3|g4|g5|g6|g7|h0|h1|h2|h3|h4|h5|h6|h7

#define B(...) A(__VA_ARGS__,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)

#include <stdio.h>

int main()
{
    printf("%d\n",B(1,2,4,8));
    printf("%d\n",B(1,2,4,8,16));
}
1赞 David Ranieri 10/7/2023 #3

使用复合文字的另一种方法:

#include <stdio.h>

#define BITWISE_OR_MULTIPLE_ARGS(...)               \
    bitwise_or_multiple_args(                       \
        (int []){__VA_ARGS__},                      \
        sizeof((int []){__VA_ARGS__}) / sizeof(int) \
    )

static int bitwise_or_multiple_args(int *arr, size_t n)
{
    int rc = 0;

    for (size_t i = 0; i < n; i++)
    {
        rc |= arr[i];
    }
    return rc;
}

int main(void)
{
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4));
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4, 8, 16));
    return 0;
}

或与可变参数函数结合使用:

#include <stdio.h>
#include <stdarg.h>

#define BITWISE_OR_MULTIPLE_ARGS(...)                   \
    bitwise_or_multiple_args(                           \
        sizeof((int []){__VA_ARGS__}) / sizeof(int),    \
        __VA_ARGS__                                     \
    )

static int bitwise_or_multiple_args(size_t n, ...)
{
    int rc = 0;
    va_list args;

    va_start(args, n);
    for (size_t i = 0; i < n; i++)
    {
        rc |= va_arg(args, int);
    }
    va_end(args);
    return rc;
}

int main(void)
{
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4));
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4, 8, 16));
    return 0;
}

在 gcc/clang 下,您可以使用语句表达式来避免辅助函数:

#include <stdio.h>

#define BITWISE_OR_MULTIPLE_ARGS(...) __extension__ \
({                                                  \
    int arr[] = {__VA_ARGS__};                      \
    size_t n = sizeof arr / sizeof(arr[0]);         \
    int rc = 0;                                     \
                                                    \
    for (size_t i = 0; i < n; i++)                  \
    {                                               \
        rc |= arr[i];                               \
    }                                               \
    rc;                                             \
})

int main(void)
{
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4));
    printf("%d\n", BITWISE_OR_MULTIPLE_ARGS(1, 2, 4, 8, 16));
    return 0;
}