Disons que j'ai un ensemble de drapeaux, encodés dans un uint16_t flags
. Par exemple AMAZING_FLAG = 0x02
,. Maintenant, j'ai une fonction. Cette fonction doit vérifier si je veux changer le drapeau, car si je veux le faire, je dois écrire en flash. Et c'est cher. Par conséquent, je veux un chèque qui me dit si flags & AMAZING_FLAG
est égal à doSet
. Ceci est la première idée:
setAmazingFlag(bool doSet)
{
if ((flags & AMAZING_FLAG) != (doSet ? AMAZING_FLAG : 0)) {
// Really expensive thing
// Update flags
}
}
Ce n'est pas une instruction if intuitive. Je pense qu'il devrait y avoir un meilleur moyen, quelque chose comme:
if ((flags & AMAZING_FLAG) != doSet){
}
Mais cela ne fonctionne pas réellement, true
semble être égal à 0x01
.
Alors, y a-t-il un bon moyen de comparer un peu à un booléen?
c
gcc
boolean
bitwise-operators
Cheiron
la source
la source
(flags & AMAZING_FLAG) && doSet
:?Réponses:
Pour convertir un nombre non nul en 1 (vrai), il existe une vieille astuce: appliquer l'
!
opérateur (pas) deux fois.la source
(bool)(flags & AMAZING_FLAG) != doSet
- que je trouve plus direct. (Bien que cela suggère que M. Microsoft a un problème avec cela.) En outre,((flags & AMAZING_FLAG) != 0)
c'est probablement exactement ce qu'il compile et est absolument explicite.((bool)(flags & AMAZING_FLAG) != doSet)
a le même effet que(((flags & AMAZING_FLAG) != 0) != doSet)
et ils compileront probablement exactement la même chose. Le suggéré(!!(flags & AMAZING_FLAG) != doSet)
est équivalent, et j'imagine qu'il compilera également la même chose. C'est entièrement une question de goût que vous pensez être plus claire: le(bool)
casting vous oblige à vous rappeler comment fonctionnent les conversions et les conversions en _Bool; cela!!
nécessite une autre gymnastique mentale, ou pour que vous connaissiez le "truc".Vous devez convertir le masque de bits en une instruction booléenne, qui en C équivaut à des valeurs
0
ou1
.(flags & AMAZING_FLAG) != 0
. La manière la plus courante.!!(flags & AMAZING_FLAG)
. Un peu commun, également OK à utiliser, mais un peu cryptique.(bool)(flags & AMAZING_FLAG)
. Chemin C moderne à partir de C99 et au-delà uniquement.Prenez l'une des alternatives ci-dessus, puis comparez-la avec votre booléen en utilisant
!=
ou==
.la source
D'un point de vue logique, ce
flags & AMAZING_FLAG
n'est qu'une opération de bits masquant tous les autres drapeaux. Le résultat est une valeur numérique.Pour recevoir une valeur booléenne, vous utiliseriez une comparaison
et peut maintenant comparer cette valeur logique à
doSet
.En C, il peut y avoir des abréviations, en raison des règles de conversion implicites des nombres en valeurs booléennes. Vous pouvez donc aussi écrire
d'écrire que plus laconique. Mais l'ancienne version est meilleure en termes de lisibilité.
la source
Vous pouvez créer un masque basé sur la
doSet
valeur:Maintenant, votre chèque peut ressembler à ceci:
Sur certaines architectures,
!!
peut être compilé en une branche et par cela, vous pouvez avoir deux branches:!!(expr)
doSet
L'avantage de ma proposition est une seule succursale garantie.
Remarque: assurez-vous de ne pas introduire de comportement indéfini en décalant vers la gauche de plus de 30 (en supposant que l'entier est de 32 bits). Ceci peut être facilement réalisé par un
static_assert(AMAZING_FLAG_IDX < sizeof(int)*CHAR_BIT-1, "Invalid AMAZING_FLAG_IDX");
la source
AMAZING_FLAG
en termes deAMAZING_FLAG_IDX
(par exemple#define AMAZING_FLAG ((uint16_t)(1 << AMAZING_FLAG_IDX))
), afin que vous n'ayez pas les mêmes données définies à deux endroits de sorte que l'une pourrait être mise à jour (par exemple, de0x4
à0x8
) tandis que l'autre (IDX
de2
) reste inchangée .Il existe plusieurs façons d'effectuer ce test:
L'opérateur ternaire peut générer des sauts coûteux:
Vous pouvez également utiliser la conversion booléenne, qui peut être efficace ou non:
Ou son alternative équivalente:
Si la multiplication est bon marché, vous pouvez éviter les sauts avec:
Si
flags
n'est pas signé et que le compilateur est très intelligent, la division ci-dessous peut se compiler en un simple décalage:Si l'architecture utilise l'arithmétique du complément à deux, voici une autre alternative:
Alternativement, on pourrait définir
flags
comme une structure avec des champs de bits et utiliser une syntaxe beaucoup plus simple et lisible:Hélas, cette approche est généralement mal vue car la spécification des champs de bits ne permet pas un contrôle précis de l'implémentation au niveau des bits.
la source