65 votes

À l’aide de si ( !! (expr)) au lieu d’if (expr)

En lisant l’exemple de code fourni par Texas Instruments pour leur SensorTag , je suis tombé sur l’extrait suivant.

La déclaration est comme ça (dans le même fichier).

Fait offrent un avantage sur ?

80voto

FUZxxl Points 21462

L'application de la logique de ne pas (!) de l'opérateur à deux reprises dans le but de normaliser la valeur 0 ou 1. Dans un contrôle de l'expression d'un if, qui ne fait aucune différence. Le if se soucie uniquement de la valeur à zéro ou différent de zéro, le peu d' !! danse est complètement inutile.

Certains de codage guides de style pourrait mandat de ce genre de danse, ce qui pourrait être la raison pour laquelle le TI code que vous avez posté n'. Je n'ai pas vu que le faire bien.

55voto

Damian Yerrick Points 2451

L'expression !!x signifie 1 si x est une vraie valeur (un nombre différent de zéro ou un pointeur non null), sinon 0. Il est équivalent à x != 0, ou à la C99 (_Bool)x mais disponible dans les compilateurs qui précèdent le C99 ou dont les développeurs ont choisi de ne pas mettre en œuvre C99 (comme cc65 qui cible les MOS 6502).

Le conditionnel comme un tout est équivalente à la suivante:

if (ioValue & IO_DATA_LED1) {
    /* what to do if the IO_DATA_LED1 bit is true */
} else {
    /* what to do if the IO_DATA_LED1 bit is false */
}

En C, cela signifie que "si le bit à bit ET de ces deux valeurs est différente de zéro, l'exécution du bloc."

Mais certains style de codage guides peuvent interdire à un au niveau du bit (&) au premier niveau d'un if déclaration de l'état, en supposant que ce soit une faute de frappe pour la logique ET (&&). C'est dans la même classe d'erreurs que l'utilisation d' = (affectation) au lieu de == (comparaison d'égalité), pour laquelle de nombreux compilateurs offrent un diagnostic. GCC Options d'Alerte décrit diagnostics comme celles-ci:

-Wlogical-op: Avertir à propos des suspects utilise des opérateurs logiques dans les expressions. Cela comprend l'utilisation d'opérateurs logiques dans des contextes où un bit par bit opérateur est susceptible d'être prévu.

-Wparentheses: Avertir si des parenthèses sont omises dans certains contextes, comme quand il y a une assignation dans un contexte où une valeur de vérité est prévu

L'utilisation d'une paraphrase, comme (a & B) != 0, (_Bool)(a & B)ou !!(a & B) communique au compilateur et à d'autres développeurs que l'utilisation d'un opérateur au niveau du bit était intentionnel.

16voto

Yakk Points 31636

En MSVC convertir un entier en une implicitement en un déclaration peut générer un avertissement. Faire via `` ne fonctionne pas. Avertissement similaire peut-être exister dans d’autres compilateurs.

Donc en supposant que le code a été compilé avec cet avertissement activée et une décision pour traiter tous les avertissement comme erreurs, à l’aide de est une façon courte et portative de dire « oui, je veux cet entier pour être un ».

4voto

technosaurus Points 1980

Bien que le silence de l'avertissement du compilateur pour la bit-wise & est la plus probable, cela ressemble à cela pourrait aussi être le résultat d'un remaniement à ajouter les énumérations, pour des raisons de lisibilité à partir de:

PIN_setOutputValue(int,int,bool); //function definition
PIN_setOutputValue(hGpioPin, Board_LED1,!!(ioValue & IO_DATA_LED1));
PIN_setOutputValue(hGpioPin, Board_LED2,!!(ioValue & IO_DATA_LED2));
//note: the !! is necessary here in case sizeof ioValue > sizeof bool
//otherwise it may only catch the 1st 8 LED statuses as @M.M points out

pour:

enum led_enum {
  Board_LED_OFF = false,
  Board_LED_ON = true
};
PIN_setOutputValue(int,int,bool); //function definition
//...
PIN_setOutputValue(hGpioPin, Board_LED1,!!(ioValue & IO_DATA_LED1)?Board_LED_ON:Board_LED_OFF);
PIN_setOutputValue(hGpioPin, Board_LED2,!!(ioValue & IO_DATA_LED2)?Board_LED_ON:Board_LED_OFF);

Depuis qu'on a dépassé les 80 limite de caractères, il a ensuite été reconstruit pour

if (!!(ioValue & IO_DATA_LED1)) {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF);
}

if (!!(ioValue & IO_DATA_LED2)) {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF);
}

Personnellement, j'aurais préféré la version initiale pour des raisons de lisibilité, mais cette version est fréquent lorsque les lignes de code sont utilisés comme une métrique (je suis surpris qu'il n'ai pas déclarer des variables pour chaque état, de définir chaque état séparément et ensuite l'utiliser).

La prochaine version de cette "Meilleure Pratique" code pourrait ressembler à:

bool boardled1State;
bool boardled2State;
//...

boardled1State = !!(ioValue & IO_DATA_LED1);
boardled2State = !!(ioValue & IO_DATA_LED2);
//...

if (boardled1State) {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF);
}

if (boardled2State) {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON);
} else {
    PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF);
}
//... and so on

Tout cela aurait pu être fait comme ceci:

for (int i=0;i<numleds;i++)
        PIN_setOutputValue(hGpioPin, i ,!!(ioValue & (1<<i)));

3voto

chux Points 13185

L'OP est de regarder quelques vieux codage de l'idiome qui avait un sens BITD (retour dans la journée).

  1. Un usage principal de l' !! a été pour gérer les implémentations C qui a converti l'expression en if(expr) de int plutôt que de tester contre zéro.

Examinons ce qui se passe lors de l' expr est converti int puis testé contre 0. (Depuis C89, c'est non-conforme comme le test doit être un test direct à l'encontre de 0)

int i;
long li;
double d;

// no problems
if (i & 5) ...
if (d > 4.0) ...

// problems
if (li & 0x10000) ...  (Hint: int is 16-bit)
if (d)                 (d might have a value outside `int` range.

// fix
if (!!(li & 0x10000))
if (!!d)

Donc, sur la pré C89 cas de déviation et non-conforme C89 et plus tard, à l'aide de !! fait face à cette faiblesse. Certaines vieilles habitudes de prendre un temps pour mourir.

  1. En début de C++, il n'y avait pas bool type. Donc le code que je voulais tester pour la franchise nécessaires à l'utilisation de l' !! idiome

    class uint256;  // Very wide integer
    uint256 x;
    
    // problem  as (int)x may return just the lower bits of x
    if (x) 
    
    // fix
    if (!!x) 
    
  2. Ce qui se passe avec C++ aujourd'hui (je sais c'est une question C) quand il n'y a pas d' (bool) définie par l'opérateur, n'est pas l' (int) opérateur utilisé? Il en résulte le même problème que le #2. Comme pour beaucoup de premières années le C et le C++ bases de code ont été synchronisé, à l'aide de !! pertinence avec des constructions comme if (!!x).


À l'aide de !! fonctionne aujourd'hui, mais qui a certainement tombé hors de la faveur, car il résout le problème ne se produit plus avec le significative de la fréquence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X