Converting a set of booleans to a number

帅比萌擦擦* 提交于 2019-12-14 04:18:09

问题


This is the code I am going to use to take a set of three booleans and convert it into an int for a switch statement:

int bits = 0;
bool a = true, b = false, c = true;  // 101 = 5

bits = bits | a << 2;
bits = bits | b << 1;
bits = bits | c;

cout << bits;

I have eight cases based on the combined state of these three booleans. Am I doing this right?

Right, not in the sense of the syntax although if there are any problems there please advise. More right in the sense of "Is this the best way to solve this problem?"


回答1:


If you are using C++, you could use bitset<N>.




回答2:


You're doing it right. You could make the code a little more succinct though:

bits |= (a<<2) | (b<<1) | (c<<0);

Just be aware that the Standard doesn't enforce any size constraint on bool. Pragmatically speaking there shouldn't be a problem with three bits, but the Standard doesn't back you here.




回答3:


$ cat ttt.c

//example of C solution
#include <stdio.h>

int main() {
        union {
                unsigned int val;
                struct {
                        unsigned a : 1;
                        unsigned b : 1;
                        unsigned c : 1;
                        //unsigned d : 1; 
                        //e, f, g, h...
                } flags;
        } bits;

        bits.val=0;
        bits.flags.a = 1;
        bits.flags.c = 1;

        printf("val: %d\n",bits.val);
        return 0;
}

~$ ./ttt

val: 5



回答4:


I would do it as:

bits = (bits << 1) | a;
bits = (bits << 1) | b;
bits = (bits << 1) | c;

which would require less maintenance work if you needed to add or to remove a flag.

However, doing this so that you can use it for a switch sounds like it might be a bad idea. Adding a flag would double the number of states you'd need to handle, and the case values would be fragile and hard to read.

But if you really must, here's another approach:

enum
{
    c_bit_offset,
    b_bit_offset,
    a_bit_offset
};

unsigned int bits =   (a << a_bit_offset)
                    | (b << b_bit_offset)
                    | (c << c_bit_offset);
switch (bits)
{
    case 0:
       /* Do something. */
       break;
    case (1 << a_bit_offset):
       /* Do something. */
       break;
    case (1 << a_bit_offset) | (1 << b_bit_offset):
       /* Do something. */
       break;
    ...
}

By the way, you probably should use unsigned int instead of int.




回答5:


You can make some defines to make easy to work with bits

#define BitSet(arg,bit) ((arg) |= (1<<bit))
#define BitClr(arg,bit) ((arg) &= ~(1<<bit)) 
#define BitFlp(arg,bit) ((arg) ^= (1<<bit)) 
#define BitTst(arg,bit) ((arg) & (1<<bit)) 

Then you can use only one char

keys = 0b00000101;
BitSet (keys,1);

This an common way to work in embedded systems.




回答6:


You can always do the conversion explicitly:

bits = bits | (a ? 1 : 0) << 2;

However I believe C/C++ will handle it implicitly, once you're using the bit-shift operator.

You should define constants for each flag, giving a name to the bit you are setting:

const int a_flag = 2;
bits = bits | (a ? 1 : 0) << a_flag;

Edit:

As you can see from the comments on my answer, most C/C++ programmers prefer to learn implicit conversions and operator precedence. Therefore your original code is "most correct".

Edit 2:

Except, you should use the |= operator:

const int a_flag = 2;
bits |= a << a_flag;


来源:https://stackoverflow.com/questions/3443751/converting-a-set-of-booleans-to-a-number

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!