|
|
Каждая вызываемая в программе функция должна быть где-то в ней определена, причем только один раз. Определение функции - это ее описание, в котором содержится тело функции. Например:
extern void swap(int*, int*); // описание void swap(int* p, int* q) // определение { int t = *p; *p = *q; *q = *t; }
Не так редки случаи, когда в определении функции не используются некоторые параметры:
void search(table* t, const char* key, const char*) { // третий параметр не используется // ... }
Как видно из этого примера, параметр не используется, если
не задано его имя. Подобные функции появляются при упрощении
программы или если рассчитывают на ее дальнейшее расширение. В
обоих случаях резервирование места в определении функции для
неиспользуемого параметра гарантирует, что другие функции,
содержащие вызов данной, не придется менять.
Уже говорилось, что функцию можно определить как подстановку
(inline). Например:
inline fac(int i) { return i<2 ? 1 : n*fac(n-1); }
Спецификация inline служит подсказкой транслятору, что вызов
функции fac можно реализовать подстановкой ее тела, а не с помощью
обычного механизма вызова функций ($$R.7.1.2). Хороший оптимизирующий
транслятор вместо генерации вызова fac(6) может просто использовать
константу 720. Из-за наличия взаиморекурсивных вызовов функций-подстановок,
а также функций-подстановок, рекурсивность которых зависит от входных
данных, нельзя утверждать, что каждый вызов функции-подстановки
действительно реализуется подстановкой ее тела. Степень оптимизации,
проводимой транслятором, нельзя формализовать, поэтому одни
трансляторы создадут команды 6*5*4*3*2*1, другие - 6*fac(5), а
некоторые ограничатся неоптимизированным вызовом fac(6).
Чтобы реализация вызова подстановкой стала возможна даже
для не слишком развитых систем программирования, нужно, чтобы не
только определение, но и описание функции-подстановки находилось
в текущей области видимости. В остальном спецификация inline
не влияет на семантику вызова.
| |