rand()/srand() 是 C 標準庫提供的偽隨機數生成器。本文深入剖析其運作機制、種子決定隨機序列、RAND_MAX 限制、線程不安全、現代替代方案,助你正確使用隨機數。
rand() 返回 0 ~ RAND_MAX (標準保證 ≥ 32767,通常為 2147483647)srand(seed) 設定初始種子,**相同種子產生完全相同序列**srand 等同 srand(1) (C99 標準)// 最常用:當前時間 (秒級) srand((unsigned)time(NULL)); // 需 #include// 進階:時間 + 進程 ID + 線程 ID (減少碰撞) srand((unsigned)(time(NULL) ^ getpid() ^ pthread_self())); // 高品質:讀取 /dev/urandom (Linux) 或 CryptGenRandom (Windows) unsigned int seed; FILE *f = fopen("/dev/urandom", "rb"); fread(&seed, sizeof(seed), 1, f); fclose(f); srand(seed);
| 誤區 | 後果 | 修正 |
|---|---|---|
迴圈內重複呼叫 srand(time(NULL)) | 同一秒內產生相同序列 | 程式啟動時**只呼叫一次** |
用 rand() % N 產生 0~N-1 | 分布不均 (模數偏差) | 用拒絕採樣或浮點縮放 |
以為 rand() 是真隨機 | 加密用途極度不安全 | 加密請用 /dev/urandom, getrandom(), arc4random() |
多線程共用 rand() | 資料競爭,序列混亂 | 用 rand_r(&seed) (POSIX) 或 C++11 <random> |
假設 RAND_MAX = 32767 | 移植到 64 位系統可能錯誤 | 始終使用 RAND_MAX 宏 |
// [0, n) 均勻分布 (拒絕採樣法)
int rand_range(int n) {
if (n <= 0) return 0;
int limit = RAND_MAX - RAND_MAX % n;
int r;
do { r = rand(); } while (r >= limit);
return r % n;
}
// [min, max] 含邊界
int rand_int(int min, int max) {
return min + rand_range(max - min + 1);
}
std::mt19937 (梅森旋轉) + std::uniform_int_distribution,高品質、類型安全、可序列化rand_r:線程安全版 rand,需自行管理種子getrandom():系統熵池直接讀取,適合加密#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand((unsigned)time(NULL)); // 僅一次!
for (int i = 0; i < 10; i++)
printf("%d ", rand() % 100 + 1); // 1~100 (教學用,實際用上述拒絕採樣)
putchar('\n');
return 0;
}
理解 srand/rand 的本質與限制,並在適當場合升級到現代隨機數庫,是編寫正確、高效、安全程式的關鍵。