Каждая из функций f1()
и f2()
выделяют память, a f2()
выполняет longjmp()
обратно в main()
(строка 51). Когда это происходит, локальные указатели (строки 39 и 48) на выделенную память пропали! Такие утечки памяти может оказаться трудно отследить, поскольку часто выделяются небольшие размеры памяти, и как таковые, они могут оставаться незамеченными в течение ряда лет[128].
Этот код явно патологический, но он предназначен для иллюстрации нашей мысли: setjmp()
и longjmp()
могут вести к трудно обнаруживаемым утечкам памяти. Предположим, что f1()
правильно вызвал free()
. Было бы далеко неочевидно, что память никогда не будет освобождена. В более крупной и более реалистичной программе, в которой longjmp()
мог быть вызван лишь посредством if
, найти такую утечку становится даже еще труднее.
Таким образом, при наличии setjmp()
и longjmp()
динамическая память должна управляться посредством глобальных переменных, а у вас должен быть код, который обнаруживает вход через longjmp()
(посредством проверки возвращаемого значения setjmp()
). Такой код должен затем освободить динамически выделенную память, которая больше не нужна.
В-шестых, longjmp()
и siglongjmp()
не следует использовать из функций, зарегистрированных посредством atexit()
(см. раздел 9.1.5.3 «Функции завершения»).
В-седьмых, setjmp()
и longjmp()
могут оказаться дорогими операциями на машинах с множеством регистров.
При наличии всех этих проблем вы должны строго рассмотреть дизайн своей программы. Если вам не нужно использовать setjmp()
и longjmp()
, то, может, стоит обойтись без их использования. Однако, если их использование является лучшим способом структурировать свою программу, продолжайте и используйте их, но делайте это осмотрительно.
12.6. Псевдослучайные числа
Многим приложениям нужны последовательности случайных чисел. Например, игровые программы, имитирующие бросание костей, раздачу карт или вращение барабанов игровой машины, нуждаются в возможности случайного выбора одного из возможных значений. (Подумайте о программе fortune
, содержащей большую коллекцию афоризмов; каждый раз при запуске она «случайно» выдает новое высказывание.) Многие криптографические алгоритмы также требуют наличия случайных чисел «высокого качества». В данном разделе описываются различные способы получения последовательностей случайных чисел.
ЗАМЕЧАНИЕ. Природа случайности, генерация случайных чисел и их «качество» являются обширными темами, выходящими за рамки данной книги. Мы предоставляем введение в доступные функции API, но это все, что мы можем сделать Другие источники с более подробной информацией см в разделе 12.9 «Рекомендуемая литература»
Компьютеры по своему строению являются
Многие методы предоставления последовательностей псевдослучайных чисел работают посредством осуществления каждый раз одного и того же вычисления с начальным значением (
12.6.1. Стандартный С: rand()
и srand()
Стандартный С определяет две связанные функции для псевдослучайных чисел.
#include
int rand(void);
void srand(unsigned int seed);
rand()
каждый раз после вызова возвращает псевдослучайное число в диапазоне от 0 до RAND_MAX
(включительно, насколько мы можем судить по стандарту C99). Константа RAND_MAX
должна быть по крайней мере 32 767; она может быть больше.