if (mask & VALUE) или if ((mask & VALUE) == VALUE)? - PullRequest
36 голосов
/ 10 января 2011

Возможно, вы знакомы со схемой enum битовой маски, например:

enum Flags {
    FLAG1 = 0x1,
    FLAG2 = 0x2,
    FLAG3 = 0x4,
    FLAG4 = 0x8,

    NO_FLAGS = 0,
    ALL_FLAGS = FLAG1 | FLAG2 | FLAG3 | FLAG4
};

f(FLAG2 | FLAG4);

Я видел много кода, который затем проверяет определенный бит в маске, такой как

if ((mask & FLAG3) == FLAG3)

Но разве это не эквивалентно этому?

if (mask & FLAG3)

Есть ли причина использовать первую версию? На мой взгляд, вторая более короткая версия более разборчива.

Может быть, оставшиеся привычки программистов на Си, которые думают, что истинные значения следует преобразовать в 1? (Хотя даже в этом случае более длинная версия имеет больше смысла в присваивании или return выражении, чем в тесте условного выражения.)

Ответы [ 6 ]

79 голосов
/ 10 января 2011

Конструкция if ((mask & FLAG3) == FLAG3) проверяет наличие в маске всех битов в FLAG3;if (mask & FLAG3) проверяет наличие любого .

Если вы знаете, что FLAG3 имеет ровно 1 установленный бит, они эквивалентны, но если вы потенциально определяете составные условия, может быть проще получитьв привычку явно проверять все биты, если вы это имеете в виду.

2 голосов
/ 10 января 2011

Даже для однобитного значения, где эти операторы фактически эквивалентны, я всегда поддерживаю явное сравнение.

  1. Это проясняет намерение. Мы действительно заинтересованы в сравнении флагов. (x & Flag) == Flag является установленным паттерном, и я могу обработать и распознать его в мгновение ока.

  2. Я обычно предпочитаю явные преобразования неявным. Я делаю исключение для состояний отказа (например, я пишу if (file) вместо if (file.good())), но при работе с числами 0 не является «состоянием отказа», это число, как и любые другие. Мне не нравится трактовать это по-другому в логическом контексте.

2 голосов
/ 10 января 2011

Когда речь идет о битах, так что вам нужно сравнить только один бит, вполне нормально иметь if(mask & value).

Но, предположим, что у вас есть IP-адрес, сохраненный в ant int32, и вы хотите узнать, является ли он 192.168.*, тогда вам нужно будет сделать:

if((ip & 0xFFFF0000) == 0xC0A80000) // assuming some endianness representation.
1 голос
/ 10 января 2011

Ваше условие будет истинным, если результат не равен нулю.В вашем примере результат обеих операций будет эквивалентен, а второй вариант может быть даже немного быстрее, потому что некоторые процессоры могут тестировать на ноль легче, чем другие произвольные числа, НО:

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

1 голос
/ 10 января 2011

if принимает логическое значение (bool).Первое выражение имеет тип bool, а второе - числовое значение, которое будет неявно преобразовано в bool.

0 голосов
/ 31 октября 2018

Первая конструкция, if (mask & FLAG3) означает «если хотя бы один общий бит находится во флаге и маске». Например, if (formats & supported_formats) будет истинно, если любой бит, общий для форматов и support_formats.

Вторая конструкция, if (mask & FLAG3) == FLAG3 означает «если все установленные биты в FLAG3 установлены в маске». Например, if (things_you_have & things_required) == things_required было бы истинно, если бы все things_required находились в things_you_have.

Вот быстрый пример некоторых особых случаев:

  • Для FLAG_WITH_EXACTLY_ONE_BIT_SET оба случая работают.
  • Для OBSOLETE_FLAG_SET_TO_ZERO первый случай всегда возвращает false.
  • Для FLAG_WITH_MULTIPLE_BITS_REQUIRED, или FLAG_WHICH_IS_REALLY_TWO_FLAGS_COMBINED_WITH_AN_OR, первый регистр возвращает true, когда не должен. Второй случай возвращается правильно.

Если у вас есть случай FLAG_WITH_EXACTLY_ONE_BIT_SET, вы должны кодировать со второй конструкцией, чтобы избежать странных проблем при изменении значения флага. Будьте явными, если ваш профилировщик не скажет вам выжать каждую операцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...