隨機數包括偽隨機數和物理隨機數,我要說的是使用rand()和srand()產生偽隨機數,儘管是偽隨機,也能滿足大部分要求。
#include <stdlib.h>int rand(void);返回一個偽隨機數,範圍是0-RAND_MAX(儘管實現不同,但至少是32767)void srand(unsigned int seed);設定偽隨機數演算法的種子
瞭解隨機數的產生,需要從它內部工作原理說起。調用rand()返回的隨機數實際上是由一個演算法產生的,此演算法會產生一個無關聯的數字序列,它需要一個種子,根據種子產生相應的數字序列,即種子不同,產生的數字序列也不同。srand()就是用來設定演算法種子的。
換一種說法,在你設定種子之時,隨機數演算法就把數字隊列安排好了,每次調用rand(),就好比從序列中pop一個數出來。
如果在調用rand()之前未設定種子,種子預設值是1,建議設定種子,相對安全
寫了一個demo看看這兩個函數的用法:
test1未設定種子,預設值是1
test2設定種子值為2
test3使用時間設定種子
#include <stdio.h>#include <stdlib.h>#include <sys/time.h>int main() { printf("test1: "); for (int i = 0; i < 10; ++i) { printf("%10d ", rand()); } printf("\n"); printf("test2: "); srand(2); for (int i = 0; i < 10; ++i) { printf("%10d ", rand()); } printf("\n"); printf("test3: "); struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_sec + tv.tv_usec); for (int i = 0; i < 10; ++i) { printf("%10d ", rand()); } printf("\n"); return 0;}
連續運行幾次的結果如下:
# ./test test1: 1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421 test2: 1505335290 1738766719 190686788 260874575 747983061 906156498 1502820864 142559277 1261608745 1380759627 test3: 1294573710 1359064005 1136018278 345608164 1963479234 965970445 1138858783 647030683 1547009306 2018312512 # ./test test1: 1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421 test2: 1505335290 1738766719 190686788 260874575 747983061 906156498 1502820864 142559277 1261608745 1380759627 test3: 1363208023 1758248775 1516950100 1372540572 324153599 1376932489 538519276 357621213 736010851 2085413972 # ./test test1: 1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421 test2: 1505335290 1738766719 190686788 260874575 747983061 906156498 1502820864 142559277 1261608745 1380759627 test3: 502196104 670340090 1579443138 1827056995 1871508517 1380041528 259014547 1145964334 1044434661 2069585472
可以發現,幾次運行結果之間,對應的前兩個數字序列是相同的,這是因為使用了相同的種子,而test3每次使用不同的種子,其產生的數字序列也不同。
所以想要使得偽隨機數更像物理隨機數,設定不同的種子是個好辦法,常見的一種方式是使用目前時間,srand(time(NULL))
假如有這樣一個需求,在較短時間內產生多個隨機字串,那麼我更推薦你使用gettimeofday()擷取時間,然後將tv_sec和tv_usec相加作為種子,tv_usec是微妙層級,保證毫秒級的不同時間是無壓力的
//random charvoid random_chars(char *buf, uint32_t len) { if (!buf || len == 0) { return; } struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_sec + tv.tv_usec); char src[] = "0123456789abcdefghijklmnopqrstuvwxyz"; uint32_t cnt = 36; for (int32_t i = 0; i < len; ++i) { buf[i] = src[rand() % 36]; } }