web-dev-qa-db-fra.com

si (masque & VALEUR) ou si ((masque & VALEUR) == VALEUR)?

Vous connaissez probablement le schéma de masque de bits enum, par exemple:

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

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

f(FLAG2 | FLAG4);

J'ai vu beaucoup de code qui teste ensuite un certain bit dans le masque comme

if ((mask & FLAG3) == FLAG3)

Mais n'est-ce pas l'équivalent?

if (mask & FLAG3)

Y a-t-il une raison d'utiliser la première version? À mon avis, la deuxième version plus courte est plus lisible.

Peut-être que les habitudes laissées par les programmeurs C qui pensent que les vraies valeurs devraient être converties en 1? (Même dans ce cas, la version la plus longue a plus de sens dans une assignation ou une instruction return que dans un test d'instruction conditionnelle.)

36
aschepler

La construction if ((mask & FLAG3) == FLAG3) teste si tous bits dans FLAG3 sont présents dans le masque; if (mask & FLAG3) teste si any sont présents.

Si vous savez que FLAG3 a exactement 1 bit défini, ils sont équivalents, mais si vous définissez potentiellement des conditions composées, il peut être plus clair de prendre l'habitude de tester explicitement tous les bits, si c'est ce que vous voulez dire.

79
David Gelhar

Quand c'est pour un bitet, vous devez donc comparer seulement un single bit, c'est correct d'avoir if(mask & value).

Mais supposons que vous ayez une adresse IP stockée sur ant int32 et que vous vouliez savoir si c’est 192.168.*, vous devrez alors:

if((ip & 0xFFFF0000) == 0xC0A80000) // assuming some endianness representation.
2
Benoit

if prend un booléen (bool). La première expression est directement du type bool, alors que la dernière est une valeur numérique qui sera implicitement convertie en bool.

1
Daniel Daranas

Votre condition sera vraie si le résultat est différent de zéro. Dans votre exemple, le résultat des deux opérations serait équivalent et la deuxième option pourrait même être légèrement plus rapide, car certains processeurs peuvent tester le zéro plus facilement que d'autres nombres arbitraires, MAIS:

Évidemment, vous ne pouvez pas utiliser la deuxième option si la valeur que vous recherchez est composée de plus d'un bit. Dans ce cas, vous devez utiliser la première option. Cela s'applique évidemment aussi si vous recherchez plusieurs bits en même temps.

1
EboMike

La première construction, if (mask & FLAG3), signifie "si au moins un bit commun se trouve dans le drapeau et le masque". Par exemple, if (formats & supported_formats) serait vrai si any bit étaient en commun entre les formats et supported_formats.

La deuxième construction, if (mask & FLAG3) == FLAG3, signifie "si tous les bits définis dans FLAG3 sont définis dans le masque". Par exemple, if (things_you_have & things_required) == things_required serait vrai si all things_quired était dans things_you_have.

Voici un coup rapide de quelques cas spéciaux:

  • Pour FLAG_WITH_EXACTLY_ONE_BIT_SET, les deux cas fonctionnent.
  • Pour OBSOLETE_FLAG_SET_TO_ZERO, le premier cas renvoie toujours false.
  • Pour FLAG_WITH_MULTIPLE_BITS_REQUIRED ou FLAG_WHICH_IS_REALLY_TWO_FLAGS_COMBINED_WITH_AN_OR, le premier cas renvoie true s'il ne le devrait pas. Le deuxième cas revient correctement.

Si vous avez le cas d'un FLAG_WITH_EXACTLY_ONE_BIT_SET, vous devez coder avec la deuxième construction pour éviter des problèmes étranges lorsque la valeur de l'indicateur est modifiée. Soyez explicite à moins que votre profileur ne vous dise de supprimer chaque opération.

0
Charles Merriam