Каждая из функций 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(), то, может, стоит обойтись без их использования. Однако, если их использование является лучшим способом структурировать свою программу, продолжайте и используйте их, но делайте это осмотрительно.

<p>12.6. Псевдослучайные числа</p>

Многим приложениям нужны последовательности случайных чисел. Например, игровые программы, имитирующие бросание костей, раздачу карт или вращение барабанов игровой машины, нуждаются в возможности случайного выбора одного из возможных значений. (Подумайте о программе fortune, содержащей большую коллекцию афоризмов; каждый раз при запуске она «случайно» выдает новое высказывание.) Многие криптографические алгоритмы также требуют наличия случайных чисел «высокого качества». В данном разделе описываются различные способы получения последовательностей случайных чисел.

ЗАМЕЧАНИЕ. Природа случайности, генерация случайных чисел и их «качество» являются обширными темами, выходящими за рамки данной книги. Мы предоставляем введение в доступные функции API, но это все, что мы можем сделать Другие источники с более подробной информацией см в разделе 12.9 «Рекомендуемая литература»

Компьютеры по своему строению являются детерминистическими. Одно и то же вычисление с одними и теми же входными данными всегда должно давать одни и те же результаты. Соответственно, они не годятся для генерации истинно случайных чисел, то есть последовательностей чисел, в которых каждое число в последовательности полностью независимо от числа (или чисел), идущих перед ним. Вместо этого разновидности чисел, обычно используемых на программном уровне, называются псевдослучайными числами. То есть в любой данной последовательности номера выглядят независимыми друг от друга, но сама последовательность в целом повторяющаяся. (Эта повторяемость может быть ценным качеством; она обеспечивает детерминизм для программы в целом.)

Многие методы предоставления последовательностей псевдослучайных чисел работают посредством осуществления каждый раз одного и того же вычисления с начальным значением (seed). Сохраненное начальное значение затем обновляется для использования в следующий раз. API предоставляет способ указания нового начального значения. Каждое начальное значение дает одну и ту же последовательность псевдослучайных чисел, хотя различные начальные числа дают (должны давать) различные последовательности.

<p>12.6.1. Стандартный С: <code>rand()</code> и <code>srand()</code></p>

Стандартный С определяет две связанные функции для псевдослучайных чисел.

#include /* ISO С */

int rand(void);

void srand(unsigned int seed);

rand() каждый раз после вызова возвращает псевдослучайное число в диапазоне от 0 до RAND_MAX (включительно, насколько мы можем судить по стандарту C99). Константа RAND_MAX должна быть по крайней мере 32 767; она может быть больше.

Перейти на страницу:

Похожие книги