既然C语言未初始化的局部变量值不确定,那么能否使用它做“随机值”呢?

在C语言程序中,未初始化的局部变量值是未定义(UB,undefined behaviour)的,使用未初始化的变量可能会为程序带来意想不到的错误,这一点看过我文章的读者应该都是清楚的。

但是,反过来想一想,“未定义的”也就意味着未初始化的局部变量内部的值是不确定的,那么它能不能被当作“随机值”使用呢?例如下面这段C语言代码:

void updateEffect(){
    for(int i=0;i<1000;i++){
        int r, g, b;
        star[i].setColor(r%255,g%255,b%255);
        bool isVisible;
        star[i].setVisible(isVisible);
    }
}

程序仅仅把未初始化的局部变量 r, g, b, isVisible 当作随机值使用,并未在其他逻辑中使用,这样做看起来要比调用 rand() 函数产生随机值效率高多了:

void updateEffect(){
    for(int i=0;i<1000;i++){
        star[i].setColor(rand()%255,rand()%255,rand()%255);
        star[i].setVisible(rand()%2==0?true:false);
    }
}

真的如此吗?

首先应该明白,计算机语言是绝对不能有歧义的,因此为C语言程序引入“未定义”的行为无疑是有违这一原则的。另外,使用未初始化局部变量作为随机值,不太可能具有理想的数学统计特性。

例如在 x86(_ 64) 架构中,从未初始化的寄存器中确实会读取出不能事先预知的值,但是这样的值并不能当作是“随机值”,因为局部变量的值存储在栈中,未初始化的值其实是栈中对应位置上一次使用者留下的。

所以如果该栈区一直没有被使用过,那么即使未初始化的局部变量也会每次都有相同的值,这显然不符合预期——产生“随机值”。换句话说,希望未初始化的局部变量提供“随机值”实在是不可靠,甚至指望它每次提供不一样的值都需要依靠运气。

即使在某段C语言代码中,未初始化的局部变量能够每次都提供不同的值,它们的数学统计特性也是不可靠的,我们不能指望它符合某种分布。

与此同时,引入“未定义”的行为到我们的C语言代码中永远是不值得推荐的做法。程序员永远都不该写不安全的代码,引入的例外越少,最终的程序就越容易避免意外错误。

因此,在C语言程序开发中,如果希望得到一个随机数,那么通过 rand() 函数获取就是最好的选择。基本上也不用担心它的效率,因为基于 rand() 函数的随机数生成器只不过是一个乘法运算,一个加法运算和一个模运算而已。

我所知道的最快的生成器是使用 uint32_t 类型作为随机变量,并且通过下面这个表达式计算:

I = 1664525 * I + 1013904223;

I 的初始值即为所谓的随机数种子,这个表达式可以产生连续的随机数。为了尽量得到高效率的随机数生成器,内联函数和函数式宏定义都是不错的选择。

上面表达式里的两个常数,是由著名的科学程序员 Donald Knuth 手工挑选的。

小结

事实上,随机性是程序开发中非常具体,又非常难以获得的属性。把一些难以追踪的(未定义)数值当作随机值,是一种常见的错误。

阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif