Если ваша система поддерживает семейство функций arc4random
, я бы рекомендовал использовать их вместо стандартной функции 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
, где предел также является 32-разрядным целым числом без знака.
arc4random_stir
считывает данные из /dev/urandom
и передает данные в arc4random_addrandom
для дополнительной рандомизации своего внутреннего пула случайных чисел.
arc4random_addrandom
используется arc4random_stir
для заполнения внутреннего пула случайных чисел в соответствии с переданными ему данными.
Если у вас нет этих функций, но вы работаете в Unix, вы можете использовать этот код:
/* 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
(легко изменяемый).
Однако /dev/urandom
может быть немного медленным, поэтому рекомендуется использовать его в качестве начального числа для другого генератора случайных чисел.
Если ваша система не имеет /dev/urandom
, но имеет файл /dev/random
или аналогичный, то вы можете просто изменить путь, переданный на open
в urandom_init
. Вызовы и API, используемые в urandom_init
и urandom
, являются (я считаю) POSIX-совместимыми и поэтому должны работать на большинстве, если не на всех POSIX-совместимых системах.
Примечания. Чтение из /dev/urandom
НЕ будет блокироваться, если недостаточно доступной энтропии, поэтому значения, генерируемые при таких обстоятельствах, могут быть криптографически небезопасными. Если вас это беспокоит, используйте /dev/random
, который всегда будет блокироваться при недостаточной энтропии.
Если вы работаете в другой системе (например, в Windows), используйте rand
или некоторый внутренний непереносимый API-интерфейс, зависящий от платформы.
Функция обертки для вызовов 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;
}