次のようなフラグ定義があると想定します。
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");
}
文字列の可能なすべての組み合わせを保持するのに十分なスペースのある文字バッファを作成し、該当するビットセットごとに適切な文字列を追加するだけです。(または、バッファを捨ててstdoutに直接書き込むこともできますが、これを選択してください)このようなことを行う方法の素朴な実装を次に示します。
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および02x」ではなく、「ビット0x1またはビット0x2」を示します。
それでも、ビット0x1と0x2の両方が値「フラグ」で「オン」になっている場合に「SOMEMSG」を出力したい場合は、次のようにします。
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);
そして最後に、ビットが設定されていない場合に印刷したくない場合は、次のようにします。
if (flag)
{
... do printing ...
}
else
{
... do nothing? ...
}