为什么arc4random()在将其存储在变量中时表现不同?

时间:2013-02-27 18:57:33

标签: ios objective-c

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

实际上,这种情况从未发生过。但

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

这里,我将随机数表达式直接放在条件中,而不是将其存储在变量中。并且条件得以实现(有时)。

为什么?我该如何调试此行为?

2 个答案:

答案 0 :(得分:6)

输入促销规则。

arc4random会返回无符号值。这意味着在第二种情况下,-5会被提升为相同的无符号类型,并将其转换为4294967291。 4亿多肯定比任何数字都大0-99!

让我们来看看你们两个例子中发生的事情。

  1. 从第一个例子开始,在这一行:

    int rand = arc4random() % 100;
    

    arc4random()返回无符号值。所以它看起来像:

    int rand = someUnsignedNumber % 100;
    

    100是一个带符号的int,因此它会被提升为与someUnsignedNumber相同的类型,并应用%操作。之后你有:

    int rand = someUnsignedNumberBetween0And99;
    

    将无符号数分配给int rand会使其返回到有符号数字。然后你的比较按预期进行。

  2. 在第二个例子中,你有这一行:

    if (arc4random() % 100 <= chance)
    

    同样的事情发生在arc4random() % 100上,产生类似的东西:

    if (someUnsignedNumberBetween0And99 <= chance)
    

    但是在这里,chance是签名号码。它会得到提升,如上所述改变它的价值,你最终会看到你所看到的奇怪行为。

答案 1 :(得分:5)

愚蠢的C型系统...如果您阅读arc4random()的{​​{3}},就会发现它的原型是

u_int32_t arc4random(void);

因此它返回无符号整数。

当将其 - unsigned - result与另一个整数进行比较时,unsignedness“wins”:另一个值(-5)被提升为无符号类型(在这种情况下为u_int32_t),它会翻转(因为无符号整数“underflow”被设计成在C中这样工作 - 你将获得2 ^ 32 - 5),因此发生了“错误的”(即表现为意外)比较。

当您明确地将值分配给int(即已签名)变量时,由于比较是在两种签名类型之间,因此不会发生此促销,因此会对其进行评估。期望的。