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