#define 宏不识别第 2 位集

#define macro doesn't identify the 2nd bit set

我有一个用于记录目的的宏。其代码如下:

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

#define BIT_IS_SET(mask, bit) ((mask) & (1 << (bit)))

typedef enum {
    LOG_STDOUT = 1 << 0,
    LOG_STDERR = 1 << 1,
    LOG_FATAL  = 1 << 2
} LOG_FLAGS;

#define QLOG(flags, fmt, ...) \
    do { \
        int use_stderr = BIT_IS_SET(flags, LOG_STDOUT) ? 1 : 0; \
        int is_fatal = BIT_IS_SET(flags, LOG_FATAL) ? 1 : 0; \
        FILE *fdesc = (use_stderr == 1) ? stdout : stderr; \
        if (use_stderr == 1) { \
            fputs("STDERR: ", fdesc); \
        } else { \
            fputs("STDOUT: ", fdesc); \
        } \
        fprintf(fdesc, "[%s]:%d: "fmt"\n", __FILE__, __LINE__, ##__VA_ARGS__); \
        if (is_fatal == 1) { \
            fputs("aboring...", fdesc); \
            fflush(fdesc); \
            abort(); \
        } \
        fflush(fdesc); \
    } while (0)

int main() 
{
    int x = 6,y = 7;
    QLOG(LOG_STDOUT, "x=%d, y=%d",x, y);
    QLOG(LOG_STDERR, "x=%d, y=%d",x, y);
    QLOG(LOG_STDOUT | LOG_FATAL, "x=%d, y=%d", x, y);
    return 0;
}

它的第一个参数是位标志(LOG_STDOUTLOG_STDERR),显示打印位置(stdoutstderr)。这些标志可以与LOG_FATAL组合,这表明必须调用abort()。在main()函数给出的测试代码中,这个LOG_FATAL没有被识别为集合。我的错误在哪里?

这是因为 & 运算符考虑了所有位。

#define BIT_IS_SET(mask, bit) ((mask) & (bit))

您不需要 do/while,括号就足够了。

考虑:

#define BIT_IS_SET(mask, bit) (!!((mask) & (bit)))

最好使用函数而不是宏。宏可能会使生成的可执行文件膨胀,而可以重新使用函数。

我认为错误在这里:

typedef enum {
    LOG_STDOUT = 1 << 0, //becomes one
    LOG_STDERR = 1 << 1, //becomes two
    LOG_FATAL  = 1 << 2  //becomes four
} LOG_FLAGS;

您的测试代码检查是否设置了第四位。在 BIT_IS_SET 的宏扩展中,您针对 1<<LOG_FATAL 进行测试,结果为 16:

int is_fatal = BIT_IS_SET(flags, LOG_FATAL) ? 1 : 0; 

这样写:

    int use_stderr = (flags) & LOG_STDOUT; \
    int is_fatal = (flags) & LOG_FATAL; \
    FILE *fdesc = use_stderr ? stdout : stderr; \
    if (use_stderr) { \
        fputs("STDERR: ", fdesc); \
    } else { \
        fputs("STDOUT: ", fdesc); \
    } \
    fprintf(fdesc, "[%s]:%d: "fmt"\n", __FILE__, __LINE__, ##__VA_ARGS__);\
    if (is_fatal) { \
        fputs("aboring...", fdesc); \
        fflush(fdesc); \
        abort(); \
    } \
    fflush(fdesc); \

还有一些东西与 LOG_STDOUT 和 LOG_STDERR 混淆了。

考虑一下您的宏扩展到什么:

BIT_IS_SET(flags, LOG_FATAL)

扩展到

((flags) & (1 << (LOG_FATAL)))

LOG_FATAL相当于1 << 2,所以这是

((flags) & (1 << (1 << 2)))

也就是

((flags) & (1 << 4))

但是当使用 LOG_FATAL 调用 QLOG 时,您传递的是 1 << 2 而不是 1 << LOG_FATAL