getpid не был объявлен.
Нет, потому что вы не включили заголовок <unistd.h>
, где он объявлен (и согласно вашему комментарию , вы не можете использовать его, потому что вы ограничены использованием <stdlib.h>
, <string.h>
и <stdio.h>
).
В этом случае я бы использовал что-то вроде
#include <stdlib.h>
#include <stdio.h>
static int randomize_helper(FILE *in)
{
unsigned int seed;
if (!in)
return -1;
if (fread(&seed, sizeof seed, 1, in) == 1) {
fclose(in);
srand(seed);
return 0;
}
fclose(in);
return -1;
}
static int randomize(void)
{
if (!randomize_helper(fopen("/dev/urandom", "r")))
return 0;
if (!randomize_helper(fopen("/dev/arandom", "r")))
return 0;
if (!randomize_helper(fopen("/dev/random", "r")))
return 0;
/* Other randomness sources (binary format)? */
/* No randomness sources found. */
return -1;
}
и простой main()
для вывода некоторых псевдослучайных чисел:
int main(void)
{
int i;
if (randomize())
fprintf(stderr, "Warning: Could not find any sources for randomness.\n");
for (i = 0; i < 10; i++)
printf("%d\n", rand());
return EXIT_SUCCESS;
}
Символьные устройства /dev/urandom
и /dev/random
доступны в Linux, FreeBSD, macOS, iOS, Solaris, NetBSD, Tru64 Unix5.1B, AIX 5.2, HP-UX 11i v2 и /dev/random
и /dev/arandom
в OpenBSD 5.1 и более поздних версиях.
Как обычно, похоже, что Windows не предоставляет таких источников случайности: программы на Windows Cвместо этого необходимо использовать проприетарные интерфейсы Microsoft.
randomize_helper()
возвращает ненулевое значение, если входной поток равен NULL или если он не может прочитать с него unsigned int
.Если он может читать из него беззнаковое целое, он используется для заполнения стандартного генератора псевдослучайных чисел, к которому вы можете получить доступ, используя rand()
(который возвращает int
в диапазоне от 0 до RAND_MAX
включительно).Во всех случаях randomize_helper()
закрывает ненулевые потоки.
Вы можете добавить другие двоичные источники случайности к randomize()
тривиально.
Если randomize()
вернет 0, rand()
должен вернутьсяпсевдослучайные числа.В противном случае rand()
вернет ту же последовательность псевдослучайных чисел по умолчанию.(Они все равно будут «случайными», но одна и та же последовательность будет происходить при каждом запуске программы. Если randomize()
вернет 0, последовательность будет отличаться при каждом запуске программы.)
Большинство стандартных реализаций C rand()
- это линейные конгруэнтные генераторы псевдослучайных чисел, часто с плохим выбором параметров, и, как следствие, медленные и не очень «случайные».
Для некриптографической работы Iхотел бы реализовать одну из функций семейства Xorshift , первоначально Джорджа Марсалья.Они очень, очень быстрые и достаточно случайные;они проходят большинство тестов статистической случайности, таких как несгибаемые тесты .
. В случае OP можно использовать генератор xorwow .Согласно действующим стандартам C, unsigned int
составляет не менее 32 бит, поэтому мы можем использовать его в качестве типа генератора.Давайте посмотрим, как будет выглядеть реализация для замены стандартного srand () / rand ():
#include <stdlib.h>
#include <stdio.h>
/* The Xorwow PRNG state. This must not be initialized to all zeros. */
static unsigned int prng_state[5] = { 1, 2, 3, 4, 5 };
/* The Xorwow is a 32-bit linear-feedback shift generator. */
#define PRNG_MAX 4294967295u
unsigned int prng(void)
{
unsigned int s, t;
t = prng_state[3] & PRNG_MAX;
t ^= t >> 2;
t ^= t << 1;
prng_state[3] = prng_state[2];
prng_state[2] = prng_state[1];
prng_state[1] = prng_state[0];
s = prng_state[0] & PRNG_MAX;
t ^= s;
t ^= (s << 4) & PRNG_MAX;
prng_state[0] = t;
prng_state[4] = (prng_state[4] + 362437) & PRNG_MAX;
return (t + prng_state[4]) & PRNG_MAX;
}
static int prng_randomize_from(FILE *in)
{
size_t have = 0, n;
unsigned int seed[5] = { 0, 0, 0, 0, 0 };
if (!in)
return -1;
while (have < 5) {
n = fread(seed + have, sizeof seed[0], 5 - have, in);
if (n > 0 && ((seed[0] | seed[1] | seed[2] | seed[3] | seed[4]) & PRNG_MAX) != 0) {
have += n;
} else {
fclose(in);
return -1;
}
}
fclose(in);
prng_seed[0] = seed[0] & PRNG_MAX;
prng_seed[1] = seed[1] & PRNG_MAX;
prng_seed[2] = seed[2] & PRNG_MAX;
prng_seed[3] = seed[3] & PRNG_MAX;
prng_seed[4] = seed[4] & PRNG_MAX;
/* Note: We might wish to "churn" the pseudorandom
number generator state, to call prng()
a few hundred or thousand times. For example:
for (n = 0; n < 1000; n++) prng();
This way, even if the seed has clear structure,
for example only some low bits set, we start
with a PRNG state with set and clear bits well
distributed.
*/
return 0;
}
int prng_randomize(void)
{
if (!prng_randomize_from(fopen("/dev/urandom", "r")))
return 0;
if (!prng_randomize_from(fopen("/dev/arandom", "r")))
return 0;
if (!prng_randomize_from(fopen("/dev/random", "r")))
return 0;
/* Other sources? */
/* No randomness sources found. */
return -1;
}
Соответствующий main()
выше будет
int main(void)
{
int i;
if (prng_randomize())
fprintf(stderr, "Warning: No randomness sources found!\n");
for (i = 0; i < 10; i++)
printf("%u\n", prng());
return EXIT_SUCCESS;
}
Обратите внимание, что PRNG_MAX
имеет двойное назначение.С одной стороны, он сообщает максимальное значение, которое prng()
может вернуть - это unsigned int, а не int, как rand()
.С другой стороны, поскольку оно должно быть 2 32 -1 = 4294967295, мы также используем его для обеспечения того, чтобы временные результаты при генерации следующего псевдослучайного числа в последовательности оставались 32-битными.Если бы был доступен тип uint32_t
, объявленный в stdint.h
или inttypes.h
, мы могли бы использовать его и отбросить маски (& PRNG_MAX
).
Обратите внимание, что функция prng_randomize_from()
написана так, чтоон все еще работает, даже если источник случайности не может предоставить все запрошенные байты одновременно, и возвращает «короткий счет» .Вопрос о том, происходит ли это на практике, остается спорным, но я предпочитаю быть уверенным.Также обратите внимание, что он не принимает состояние, если все его нули, так как это единственное запрещенное начальное начальное состояние для Xorwow PRNG.
Очевидно, вы можете использовать как srand()
/ rand()
, так и prng()
/ prng_randomize()
в той же программе.Я написал их так, чтобы все функции генератора Xorwow начинались с prng.
Обычно я помещаю реализацию PRNG в заголовочный файл, чтобы можно было легко протестировать ее (чтобы убедиться, что она работает), написав крошечныйтестовая программа;но также, чтобы я мог переключить реализацию PRNG, просто переключившись на другой заголовочный файл.(В некоторых случаях я помещаю состояние PRNG в структуру, и вызывающий абонент предоставляет указатель на состояние, так что любое количество PRNG может использоваться одновременно, независимо друг от друга.)