Преобразование набора логических значений в число - PullRequest
4 голосов
/ 10 августа 2010

Это код, который я собираюсь использовать, чтобы взять набор из трех логических значений и преобразовать его в целое число для оператора switch:

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;

У меня есть восемь случаев, основанных на комбинированномтри логических значения.Я правильно это делаю?

Правильно, не в смысле синтаксиса, хотя, если есть какие-то проблемы, пожалуйста, сообщите.Правильнее в смысле «Это лучший способ решить эту проблему?»

Ответы [ 6 ]

4 голосов
/ 10 августа 2010

Если вы используете C ++, вы можете использовать bitset<N>.

1 голос
/ 10 августа 2010

$ 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
1 голос
/ 10 августа 2010

Вы делаете это правильно.Вы могли бы сделать код немного более лаконичным, хотя:

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

Просто имейте в виду, что Стандарт не устанавливает никаких ограничений на размер bool.Прагматически говоря, не должно быть проблем с тремя битами, но Стандарт не поддерживает вас здесь.

0 голосов
/ 10 августа 2010

Вы можете сделать некоторые определения, чтобы облегчить работу с битами

#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)) 

Тогда вы можете использовать только один символ

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

Это распространенный способ работы во встроенных системах.

0 голосов
/ 10 августа 2010

Я бы сделал это следующим образом:

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

, что потребовало бы меньшего количества работ по техническому обслуживанию, если бы вам потребовалось добавить или удалить флаг.

Однако, сделав это, вы можете использоватьэто для switch звучит так, как будто это плохая идея.Добавление флага удвоит число состояний, которые вам нужно обработать, и значения case будут хрупкими и трудными для чтения.

Но если вам действительно нужно, вот другой подход:

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;
    ...
}

Кстати, вы, вероятно, должны использовать unsigned int вместо int.

0 голосов
/ 10 августа 2010

Вы всегда можете выполнить преобразование явно:

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

Однако я считаю, что C / C ++ будет обрабатывать его неявно, как только вы используете оператор сдвига битов.

Вам следуетОпределите константы для каждого флага, задав имя биту, который вы устанавливаете:

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

Редактировать:

Как видно из комментариев к моему ответу,большинство программистов на C / C ++ предпочитают изучать неявные преобразования и приоритет операторов.Поэтому ваш исходный код является «наиболее правильным».

Редактировать 2:

Кроме того, вы должны использовать оператор |=:

const int a_flag = 2;
bits |= a << a_flag;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...