假设有标志定义,例如:
SHF_WRITE 0x1
SHF_ALLOC 0x2
SHF_EXECINSTR 0x4
SHF_MASKPROC 0xf0000000
给定一个标志,我需要输出SHF_WRITE|SHF_ALLOC
位0x1
和0x2
是否打开。
如何在 C 中实现技巧?
#define V(n) { n, #n }
struct Code {
int value;
char *name;
} decode[] = {
V(SHF_WRITE),
V(SHF_ALLOC),
{ 0, NULL },
};
void f(const int x) {
struct Code *c = decode;
int beenthere = 0;
for(; c->name; ++c)
if(x & c->value)
printf("%s%s", beenthere++ ? "|" : "", c->name);
if(beenthere)
printf("\n");
}
只需创建一个具有足够空间的字符缓冲区来保存所有可能的字符串组合,并为每个适用的位集添加适当的字符串。(或者你可以放弃缓冲区并直接写入标准输出,你的选择)这是一个简单的实现,你可以如何做这样的事情:
void print_flags(int flag)
{
#define BUFLEN (9+9+13+12+3+1)
/* for the text, pipes and null terminator*/
#define PAIRLEN 4
static struct { int value; const char *string; } pair[] =
{
{ SHF_WRITE, "SHF_WRITE" },
{ SHF_ALLOC, "SHF_ALLOC" },
{ SHF_EXECINSTR, "SHF_EXECINSTR" },
{ SHF_MASKPROC, "SHF_MASKPROC" },
};
char buf[BUFLEN]; /* declare the buffer */
char *write = buf; /* and a "write" pointer */
int i;
for (i = 0; i < PAIRLEN; i++)
{
if ((flag & pair[i].value) == pair[i].value) /* if flag is set... */
{
size_t written = write - buf;
write += _snprintf(write, BUFLEN-written, "%s%s",
written > 0 ? "|" : "",
pair[i].string); /* write to the buffer */
}
}
if (write != buf) /* if any of the flags were set... */
{
*write = '\0'; /* null terminate (just in case) */
printf("(%s)", buf); /* print out the buffer */
}
#undef PAIRLEN
#undef BUFLEN
}
问题:
“SHF_WRITE|SHF_ALLOC”表示“位 0x1 或位 0x2”,而不是“位 0x1 和 02x”。
不过,如果您想在某个值“flag”中位 0x1 和 0x2 都“on”时打印“SOME MSG”,请执行以下操作:
if (flag & SHF_WRITE & SHF_ALLOC)
printf ("SOME MSG, flag= 0x%x\n", flag);
如果您想打印值中“打开”的任何位的文本表示,您可以执行以下操作:
char buf[80] = '\0';
if (flag & SHF_WRITE)
strcpy (buf, " SHF_WRITE");
if (flag & SHF_ALLOC)
strcpy (buf, " SHF_ALLOC");
...
printf ("SOME MSG, flag= %s\n", buf);
最后,如果您不想在设置 NO 位的情况下打印,请执行以下操作:
if (flag)
{
... do printing ...
}
else
{
... do nothing? ...
}