Pourquoi arc4random () se comporte-t-il différemment lorsqu'il est stocké dans une variable ou non?

int chance = -5; int rand = arc4random() % 100; // Number from 0 to 99 if (rand <= chance) { // This will never happen NSLog(@"This is... NOT POSSIBLE"); } 

Effectivement, cela n'arrive jamais. Mais

  int chance = -5; if (arc4random() % 100 <= chance) { NSLog(@"This is... NOT POSSIBLE"); } 

Ici, au lieu de le stocker dans une variable, j'ai placé l'expression de nombre random directement dans la condition. Et la condition est remplie (parfois).

Pourquoi donc? Comment puis-je déboguer ce comportement?

Tapez les règles de promotion.

arc4random renvoie une valeur non signée . Cela signifie que dans votre deuxième cas, le -5 est promu au même type non signé, le transformant en 4294967291 . 4+ milliards est nettement plus grand que n'importe quel nombre 0-99!

Passons en revue ce qui se passe dans vos deux exemples.

  1. De votre premier exemple, dans cette ligne:

     int rand = arc4random() % 100; 

    arc4random() renvoie une valeur non signée. Alors ça ressemble à:

     int rand = someUnsignedNumber % 100; 

    Le 100 est un int signé, donc il est promu au même type que someUnsignedNumber , et l'opération % est appliquée. Après cela, vous avez:

     int rand = someUnsignedNumberBetween0And99; 

    L'affectation de ce nombre non signé à int rand le ramène à un nombre signé. Votre comparaison se poursuit comme prévu.

  2. Dans le deuxième exemple, vous avez cette ligne:

     if (arc4random() % 100 <= chance) 

    Les mêmes choses se produisent avec arc4random() % 100 , ce qui donne quelque chose comme:

     if (someUnsignedNumberBetween0And99 <= chance) 

    Mais ici, le chance est un nombre signé. Il obtient promu, en changeant sa valeur comme décrit ci-dessus, et vous vous retrouvez avec le comportement étrange que vous voyez.

Silly, système de type stupide de C … Si vous lisez la page man pour arc4random() , vous découvrez que son prototype est

 u_int32_t arc4random(void); 

Il renvoie donc un entier non signé .

En comparant son résultat – unsigned – avec un autre entier, le non-signe "gagne": l'autre valeur ( -5 ) est promue au type non signé ( u_int32_t dans ce cas), elle survole (puisque l'entier non signé "underflow" est conçu pour travaillez comme ceci en C – vous obtiendrez 2 ^ 32 - 5 ) et donc une comparaison "erronée" (c'est-à-dire se comporter comme inattendue) se produit.

Lorsque vous atsortingbuez explicitement la valeur à une variable int (c'est-à-dire signée ), cette promotion ne se produit pas car la comparaison se fait entre deux types signés, elle est donc évaluée comme vous le souhaitez.