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

Vol*_*ort 3 objective-c ios

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

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

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

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

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

Car*_*rum 6

输入促销规则.

arc4random返回无符号值.这意味着在第二种情况下,-5将其提升为相同的无符号类型,将其转换为4294967291.4亿多肯定比0-99更大!

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

  1. 从您的第一个示例开始,在此行中:

    int rand = arc4random() % 100;
    
    Run Code Online (Sandbox Code Playgroud)

    arc4random()返回无符号值.那么它看起来像:

    int rand = someUnsignedNumber % 100;
    
    Run Code Online (Sandbox Code Playgroud)

    100是一个signed int,因此它被提升为与之相同的类型someUnsignedNumber,并应用了该%操作.之后你有:

    int rand = someUnsignedNumberBetween0And99;
    
    Run Code Online (Sandbox Code Playgroud)

    分配该无符号数字int rand使其返回有符号数字.然后您的比较按预期进行.

  2. 在第二个示例中,您有以下这一行:

    if (arc4random() % 100 <= chance)
    
    Run Code Online (Sandbox Code Playgroud)

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

    if (someUnsignedNumberBetween0And99 <= chance)
    
    Run Code Online (Sandbox Code Playgroud)

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


小智 5

傻,C傻类型系统......如果你读了man页面arc4random(),你会发现,它的原型是

u_int32_t arc4random(void);
Run Code Online (Sandbox Code Playgroud)

所以它返回一个无符号整数.

当将其 - unsigned - 结果与另一个整数进行比较时,unsignedness"wins":另一个value(-5)被提升为无符号类型(u_int32_t在本例中),它会翻转(因为无符号整数"underflow"设计为像这样工作在C - 你会得到2 ^ 32 - 5)因此发生"错误"(即表现为意外)的比较.

当您将值显式分配给int(即已签名)变量时,由于比较是在两个签名类型之间,因此不会发生此促销,因此会按预期进行评估.