Хрестоматия по программированию на Си в Unix


Простые программы и алгоритмы. Сюрпризы, советы. Хрестоматия по программированию на Си в Unix - стр. 2


.

Функция, которая

  • не содержит внутри себя статических переменных, хранящих состояние процесса обработки данных (функция без "памяти");
  • получает значения параметров только через свои аргументы (но не через глобальные статические переменные);
  • возвращает значения только через аргументы, либо как значение функции (через return);

называется реентерабельной (повторно входимой) или чистой (pure). Такая функция может параллельно (или псевдопараллельно) использоваться несколькими "потоками" обработки информации в нашей программе, без какого-либо непредвиденного влияния этих "потоков обработки" друг на друга. Первый пункт требований позволяет функции не зависеть ни от какого конкретного процесса обработки данных, т.к. она не "помнит" обработанных ею ранее данных и не строит свое поведение в зависимости от них. Вторые два пункта - это требование, чтобы все без исключения пути передачи данных в функцию и из нее (интерфейс функции) были перечислены в ее заголовке. Это лишает функцию "побочных эффектов", не предусмотренных программистом при ее вызове (программист обычно смотрит только на заголовок функции, и не выискивает "тайные" связи функции с программой через глобальные переменные, если только это специально не оговорено).

Вот пример не реентерабельной функции:

FILE *fp; ... /* глобальный аргумент */ char delayedInput () { static char prevchar; /* память */ char c; c = prevchar; prevchar = getc (fp); return c; }

А вот ее реентерабельный эквивалент:

char delayedInput (char *prevchar, FILE *fp) { char c; c = *prevchar; *prevchar = getc (fp); return c; } /* вызов: */ FILE *fp1, *fp2; char prev1, prev2, c1, c2; ... x1 = delayedInput (&prev1, fp1); x2 = delayedInput (&prev2, fp2); ...

Как видим, все "запоминающие" переменные (т.е. prevchar) вынесены из самой функции и подаются в нее в виде аргумента.

Реентерабельные функции независимы от остальной части программы (их можно скопировать в другой программный проект без изменений), более понятны (поскольку все затрагиваемые ими внешние переменные перечислены как аргументы, не надо выискивать в теле функции глобальных переменных, передающих значение в/из функции, т.е. эта функция не имеет побочных влияний), более надежны (хотя бы потому, что компилятор в состоянии проверить прототип такой функции и предупредить вас, если вы забыли задать какой-то аргумент; если же аргументы передаются через глобальные переменные - вы можете забыть проинициализировать какую-то из них). Старайтесь делать функции реентерабельными!

Вот еще один пример на эту тему. Не-реентерабельный вариант:




- Начало -  - Назад -  - Вперед -



Книжный магазин