Почему побитовая логика OR и AND не работает должным образом? - PullRequest
1 голос
/ 08 октября 2019

У меня есть пример кода ниже. У меня всегда было впечатление, что выполнение побитового ИЛИ для значений перечисления позволит мне проверить результат (используя побитовое И), чтобы увидеть, какие значения перечисления включены в результат, а какие нет.

Например, если я сделаю result = mouse | headphone, тогда я могу проверить agaist result & mouse == mouse в качестве условия, чтобы узнать, включен ли mouse в result или нет. Но, похоже, что все, что я & получаю, скажем, X, я всегда получаю в результате X. Почему?

В приведенном ниже коде я подумал, что if должен завершиться неудачей, поскольку straw не был включен вoptions, но это не так.

#include <iostream>
#include <iomanip>

using namespace std;

enum Stock  
{
    milk,
    choclate,
    tv,
    cable,
    mouse,
    fan,
    headphone,
    cup,
    straw,
    pen,
    candy,
    glasses,
    book,
    plug

};


int main()
{
    Stock options = static_cast<Stock>( static_cast<int>(mouse) | static_cast<int>(headphone)
                                            | static_cast<int>(cup) | static_cast<int>(pen)     );

    if ((static_cast<int>(loptions)) & (static_cast<int>(straw)) == static_cast<int>(straw))
    {
        cout << "bring straw!" << endl;
    }

    system("PAUSE");
    return 0;
}

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

Даже когда я добавляю уникальный битовый набор для значений перечисления, он не работает,Для приведенного ниже кода он игнорирует оба оператора if (), когда я ожидаю, что вместо него будет отображаться "bring cup":

enum Stock
{
    milk = 1,
    choclate = 2,
    tv = 4,
    cable = 8,
    mouse = 16,
    fan = 32,
    headphone = 64,
    cup = 128,
    straw = 256,
    pen = 512,
    candy = 1024,
    glasses = 2048,
    book = 4096,
    plug = 8192

};


int main()
{
    Stock options = static_cast<Stock>(static_cast<int>(mouse) | static_cast<int>(headphone)
                                        | static_cast<int>(cup) | static_cast<int>(pen));

    if ((static_cast<int>(options)) & (static_cast<int>(straw)) == static_cast<int>(straw))
    {
        cout << "bring straw!" << endl;
    }

    if ((static_cast<int>(options)) & (static_cast<int>(cup)) == static_cast<int>(cup))
    {
        cout << "bring cup!" << endl;
    }

    system("PAUSE");
    return 0;
}

1 Ответ

2 голосов
/ 08 октября 2019

Чтобы использовать перечисления в качестве наборов битов (или флагов), необходимо убедиться, что двоичное представление для каждого значения перечисления содержит ровно один бит, установленный в 1. Другими словами, каждое значение перечисления должно быть степенью двойки. Пример:

enum Stock  
{
    milk = 1,     // 0x0001
    choclate = 2, // 0x0010
    tv = 4,       // 0x0100
    cable = 8     // 0x1000
    // etc.
};

В противном случае побитовые логические операторы не смогут различать определенные значения и определенные комбинации других значений. Например, рассмотрим оригинальный код. chocolate, tv и cable имеют значения 1, 2 и 3 соответственно. В двоичном коде это 01, 10 и 11. ИЛИ chocolate и tv выдают 11 (0b01 | 0b10 == 0b11), что соответствует значению cable. Комбинация chocolate и tv неотличима от флага cable.

Но c ++ обеспечивает std::bitset. Этот класс позволяет легко манипулировать набором битов аналогично массиву битов. Затем вы можете просто использовать свое исходное перечисление и использовать каждое значение перечисления в качестве индекса бита.

...