我在一个古老而尘土飞扬的项目中找到了这段代码:
int *p = (int*)malloc(sizeof(p)); // generate random number
free(p); // free up space
int rand = p%3; // get random value in between 0-2
除了我们在C标准库中获得srand之外它是不好的样式和不必要的,返回值的实际随机性是多少?
虽然在使用它的上下文中不需要真正的随机性,但我每次测试它的次数为99999999次,并且每次测试运行rand == 0
都比其他情况(rand == 1
更少。和rand == 2
)。
一个例子:
rand == 0
:在99999999中有27343746次rand == 1
:99999999中的36328138次rand == 2
:在99999999中有36328115次答案 0 :(得分:2)
这是获取随机数的一种非常愚蠢的方式。它的行为非常依赖于平台以及应用程序代码正在做什么。例如,如果你在没有进行其他内存分配的循环中调用它,那么在许多系统上free
将一遍又一遍地返回相同的块,因为p
将它返回到免费的前面列表,所以每次rand==0
都是一样的。在许多其他的情况下,当堆增长到一定大小时,最终会得到一个循环,然后分配器循环通过多个插槽。
这一特殊可能性显然在您的实验中发生了什么:您在70/256个案例中获得rand==1
,在93/256个案例中获得rand==2
和p
(除此之外,可能来自前几个尚未达到周期的分配和最后一个部分周期)。我不太熟悉malloc实现来解释这个特定的分布;可能malloc使用的控制结构的大小是3的倍数,这会产生模3的偏差。
模数为2的幂,你会在每个现实平台上产生偏差,因为保证任何类型的返回值都能正确对齐,并且大多数平台对2的幂都有对齐约束。或者换句话说, rand
的最低位总是很少。
malloc
是标准的C,并且在大多数平台上都很糟糕(甚至没有考虑将它用于与安全相关的任何事情,甚至对于概率算法来说它通常也不够好),它很少会比malloc
输出更差。
可能有一些平台,其中{{1}}的返回值被随机化以利用缓冲区溢出和免费使用后的错误(因为攻击者无法预测有趣的对象在哪里)将与ASLR)一样,但这样的平台无论如何都会有更好的随机生成器API。