#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_STDOUT
或 LOG_STDERR
),显示打印位置(stdout
或 stderr
)。这些标志可以与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
我有一个用于记录目的的宏。其代码如下:
#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_STDOUT
或 LOG_STDERR
),显示打印位置(stdout
或 stderr
)。这些标志可以与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