# 如何在C中生成一个随机数？

` `#include <time.h> #include <stdlib.h> srand(time(NULL)); // should only be called once int r = rand(); // returns a pseudo-random integer between 0 and RAND_MAX` `

`<stdlib.h>``rand()`函数返回0到`RAND_MAX`之间的伪随机整数。 你可以使用`srand(unsigned int seed)`来设置种子。

`rand()`运算符与`rand()`结合使用以获得不同的范围是很常见的做法（不过要记住，这会在一定程度上影响均匀性）。 例如：

` `/* random int between 0 and 19 */ int r = rand() % 20;` `

` `/* Returns an integer in the range [0, n). * * Uses rand(), and so is affected-by/affects the same seed. */ int randint(int n) { if ((n - 1) == RAND_MAX) { return rand(); } else { // Chop off all of the values that would cause skew... long end = RAND_MAX / n; // truncate skew assert (end > 0L); end *= n; // ... and ignore results from rand() that fall above that limit. // (Worst case the loop condition should succeed 50% of the time, // so we can expect to bail out of this loop pretty quickly.) int r; while ((r = rand()) >= end); return r % n; } }` `

### 如果你需要安全的随机字符或整数：

• 使用libsodium的`randombytes` API
• 重新执行你自己需要的libsodium的sysrandom实现 ，非常仔细
• 更广泛地说， 使用`/dev/urandom` ，而不是`/dev/random` 。 不是OpenSSL（或其他用户空间PRNG）。

` `#include "sodium.h" int foo() { char myString[32]; uint32_t myInt; /* myString will be an array of 32 random bytes, not null-terminated */ randombytes_buf(myString, 32); /* myInt will be a random number between 0 and 9 */ myInt = randombytes_uniform(10); }` `

`randombytes_uniform()`是密码安全且无偏见的。

` `#include <stdio.h> int random_number(int min_num, int max_num); int main(void) { printf("Min : 1 Max : 40 %d\n", random_number(1,40)); printf("Min : 100 Max : 1000 %d\n",random_number(100,1000)); return 0; } int random_number(int min_num, int max_num) { int result = 0, low_num = 0, hi_num = 0; if (min_num < max_num) { low_num = min_num; hi_num = max_num + 1; // include max_num in output } else { low_num = max_num + 1; // include max_num in output hi_num = min_num; } srand(time(NULL)); result = (rand() % (hi_num - low_num)) + low_num; return result; }` `

` `#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <openssl/rand.h> /* Random integer in [0, limit) */ unsigned int random_uint(unsigned int limit) { union { unsigned int i; unsigned char c[sizeof(unsigned int)]; } u; do { if (!RAND_bytes(uc, sizeof(uc))) { fprintf(stderr, "Can't get random bytes!\n"); exit(1); } } while (ui < (-limit % limit)); /* ui < (2**size % limit) */ return ui % limit; } /* Random double in [0.0, 1.0) */ double random_double() { union { uint64_t i; unsigned char c[sizeof(uint64_t)]; } u; if (!RAND_bytes(uc, sizeof(uc))) { fprintf(stderr, "Can't get random bytes!\n"); exit(1); } /* 53 bits / 2**53 */ return (ui >> 11) * (1.0/9007199254740992.0); } int main() { printf("Dice: %d\n", (int)(random_uint(6) + 1)); printf("Double: %f\n", random_double()); return 0; }` `

OpenSSL的`RAND_bytes()`种子本身，也许通过阅读Linux中的`/dev/urandom` 。 如果我们需要很多随机数，那么从`/dev/urandom`读取所有数据将会非常慢，因为它们必须从内核复制。 允许OpenSSL从种子生成更多的随机数字会更快。

• Perl的Perl_seed（）是一个如何计算`srand()`中C的种子的例子。 如果不能读取`/dev/urandom` ，它会混合当前时间，进程ID和一些指针。
• OpenBSD的arc4random_uniform（）解释了模偏移。
• java.util.Random的Java API描述了用于从随机整数中去除偏倚的algorithm，并将53位打包成随机的浮点数。

STL对于C不存在。您必须调用`rand` ，或者更好， `random` 。 这些是在标准库头`stdlib.h`中声明的。 `rand`是POSIX， `random`是BSD spec函数。

`rand``random`之间的区别是`random`返回一个更有用的32位随机数，而`rand`通常返回一个16位数。 BSD手册页显示`rand`的低位是循环的和可预测的，所以`rand`对于小数是没有用的。

`arc4random`系列包括：

` `uint32_t arc4random(void) void arc4random_buf(void *buf, size_t bytes) uint32_t arc4random_uniform(uint32_t limit) void arc4random_stir(void) void arc4random_addrandom(unsigned char *dat, int datlen)` `

`arc4random`返回一个随机的32位无符号整数。

`arc4random_buf`将随机内容放入参数`buf : void *` 。 内容量由`bytes : size_t`参数决定。

`arc4random_uniform`返回一个随机的32位无符号整数，它遵循以下规则： `0 <= arc4random_uniform(limit) < limit` ，其中limit也是一个无符号的32位整数。

`arc4random_stir``/dev/urandom`读取数据，并将数据传递给`arc4random_addrandom`以另外随机化它的内部随机数字池。

`arc4random_addrandom``arc4random_stir`根据传递给它的数据填充它的内部随机数池。

` `/* This is C, not C++ */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> /* exit */ #include <stdio.h> /* printf */ int urandom_fd = -2; void urandom_init() { urandom_fd = open("/dev/urandom", O_RDONLY); if (urandom_fd == -1) { int errsv = urandom_fd; printf("Error opening [/dev/urandom]: %i\n", errsv); exit(1); } } unsigned long urandom() { unsigned long buf_impl; unsigned long *buf = &buf_impl; if (urandom_fd == -2) { urandom_init(); } /* Read 4 bytes, or 32 bits into *buf, which points to buf_impl */ read(urandom_fd, buf, sizeof(long)); return buf_impl; }` `

`urandom_init`函数打开`/dev/urandom`设备，并将文件描述符放入`urandom_fd`

`urandom`函数基本上和`rand`的调用一样，除了更安全，它返回一个`long` （很容易改变）。

`urandom``rand``arc4random`调用的包装函数：

` `#define RAND_IMPL /* urandom(see large code block) | rand | arc4random */ int myRandom(int bottom, int top){ return (RAND_IMPL() % (top - bottom)) + bottom; }` `

FWIW，答案是肯定的，有一个叫做`rand``stdlib.h`函数; 这个function主要是为了速度和分配而调整的，而不是不可预测的。 几乎所有内置的各种语言和框架的随机函数默认使用这个函数。 也有“密码”随机数发生器，可预测性更差，但运行速度慢得多。 这些应该用于任何types的安全相关的应用程序。

` `int rand(void); void srand(unsigned seed);` `

` `long random(void);` `

` `#include <time.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { srand((unsigned int)**main + (unsigned int)&argc + (unsigned int)time(NULL)); srand(rand()); for (int i = 0; i < 10; i++) printf("%d\n", rand()); }` `

`rand()`是生成随机数最方便的方法。

` `#include <stdio.h> #include <stdlib.h> #include <time.h> #define randnum(min, max) \ ((rand() % (int)(((max) + 1) - (min))) + (min)) int main() { srand(time(NULL)); printf("%d\n", randnum(1, 70)); }` `

` `#include <stdio.h> #include <dos.h> int random(int range); int main(void) { printf("%d", random(10)); return 0; } int random(int range) { struct time t; int r; gettime(&t); r = t.ti_sec % range; return r; }` `
` `#include <stdio.h> #include <stdlib.h> void main() { int visited[100]; int randValue, a, b, vindex = 0; randValue = (rand() % 100) + 1; while (vindex < 100) { for (b = 0; b < vindex; b++) { if (visited[b] == randValue) { randValue = (rand() % 100) + 1; b = 0; } } visited[vindex++] = randValue; } for (a = 0; a < 100; a++) printf("%d ", visited[a]); }` `

` `#include <stdio.h> #include <stdlib.h> #include <time.h> int main(int argc, char *argv[]) { int i; int dice[6]; for (i = 0; i < 6; i++) dice[i] = 0; srand(time(NULL)); const int TOTAL = 10000000; for (i = 0; i < TOTAL; i++) dice[(rand() % 6)] += 1; double pers = 0.0, tpers = 0.0; for (i = 0; i < 6; i++) { pers = (dice[i] * 100.0) / TOTAL; printf("\t%1d %5.2f%%\n", dice[i], pers); tpers += pers; } printf("\ttotal: %6.2f%%\n", tpers); }` `

` ` \$ gcc -o t3 t3.c \$ ./t3 1666598 16.67% 1668630 16.69% 1667682 16.68% 1666049 16.66% 1665948 16.66% 1665093 16.65% total: 100.00% \$ ./t3 1667634 16.68% 1665914 16.66% 1665542 16.66% 1667828 16.68% 1663649 16.64% 1669433 16.69% total: 100.00%` `

` `srand(time(NULL))` `

• rand将产生相同的伪随机序列，在srand中给出相同的种子（参见`man srand` ）;
• 如前所述，时间函数仅从第二个变为第二个：如果您的应用程序在同一秒内运行多次，则`time`将每次返回相同的值。

1. 混合时间输出与一些其他信息在运行（在我的应用程序，输出名称）更改：

` `srand(time(NULL) | getHashOfString(outputName))` `

我用djb2作为我的散列函数。

2. 增加时间分辨率。 在我的平台上， `clock_gettime`可用，所以我使用它：

` `#include<time.h> struct timespec nanos; clock_gettime(CLOCK_MONOTONIC, &nanos) srand(nanos.tv_nsec);` `
3. 一起使用两种方法：

` `#include<time.h> struct timespec nanos; clock_gettime(CLOCK_MONOTONIC, &nanos) srand(nanos.tv_nsec | getHashOfString(outputName));` `

C程序生成9到50之间的随机数

` `#include <time.h> #include <stdlib.h> int main() { srand(time(NULL)); int lowerLimit = 10, upperLimit = 50; int r = lowerLimit + rand() % (upperLimit - lowerLimit); printf("%d", r); }` `

` `#include <immintrin.h> uint64_t randVal; if(!_rdrand64_step(&randVal)) { // Report an error here: random number generation has failed! } // If no error occured, randVal contains a random 64-bit number` `

` `int range_rand(int min_num, int max_num) { if(min_num >= max_num) { fprintf(stderr, "min_num is greater or equal than max_num!\n"); } return min_num + (rand() % (max_num - min_num)); }` `

` `/* Uses the srand() function to seed the random number generator based on time value, then returns an integer in the range 1 to max. Call this with random(n) where n is an integer, and you get an integer as a return value. */ int random(int max) { srand((unsigned) time(NULL)); return (rand() % max) + 1; }` `