Тема 3. Подстановка

Вызов функции это операция, включающая в себя несколько шагов. Поэтому использование функций плохо сказывается на быстродействии кода, но это осознанная жертва, поскольку значительно повышается читаемость кода программы, улучшается ее структурированность. Однако не всегда логически верное выделение фрагмента кода выгодно с точки зрения производительности. Чаще всего такая ситуация возникает, когда функция выполняет ряд простых арифметических действий. В таких случаях следует использовать макросы препроцессора или подстановочные функции.

Макросы препроцессора

Существуют два типа макросов: макрос-объект(object-like macro) и макрос-функция(function-like macro), оба типа объявляются с помощью директивы #define. Рассмотрим сначала макросы-объекты. Объявляются они как:
#define ИМЯ_МАКРОСА [замещающий текст]
Всё, что идёт после имя макроса до конца строки является замещающим текстом. При помощи макросов-объектов часто определяются константы или часто встречающиеся последовательности переменных и аврифметических операторов:


Однако следует помнить, что макрос это просто подстановка а не переменная, то есть везде где встречается символ N при трансляции программы символ заменяется на его то что в определении идет после имени, то есть в данном случае на число 10. С одиночным символом это не страшно, но при использовании выражения может получиться не верный результат. Например, если на каждом шаге цикла надо не только прибавлять значение i, но и увеличивать получившееся значение вдвое, то приведенный ниже код даст ошибочный результат:

Второй вид макросов — это макро-функции (function-like macros). Определяются они с помощью той-же директивы #define, после которой (сразу без пробелов) в круглых скобках идёт список разделённых запятыми аргументов:

Важным моментом является то, что делитель x также заключен в скобки. Посмотрим, что будет если его не заключать в скобки...


Видно, что во втором случае результат не верный. Все объясняется тем, что макрос препроцессора это просто подстановка, а не функция. То есть при компиляции в строке 21 мы получаем следующее выражение:

val = (a + b + c)/(a+b+c)

А во втором случае (строка 24) получаем:

val = (a + b + c)/a+b+c

то есть периметр делится на длину стороны a, а затем к результату деления прибавляются длины сторон b и c.





Подстановочные функции (inline)

Подстановочные функции (функции-подстановки) это участки кода, оформленные как полноценные функции, но компиляторуЮ дается команда рассматривать их как подстановку и не формировать полноценный вызов функции со всеми его многоходовыми действиями. Конечно такое возможно не всегда, поэтому компилятор оценивает возможность реализации подстановки, если такой возможности нет, то оформляется стандартный вызов. Таким образом, код inline-функции должен быть очень простым.

Встраиваемая функция описывается точно также, как и обычная, но ее заголовок предваряется служебным словом inline:

inline float Perimetr(float a, float b, float c)
{
	 return a + b + c; 
}

Как только компилятор встречает служебное слово inline, он воспринимает это как команду вставить тело функции в код основной программы без оформления вызова функции. В результате используется преимущество быстродействующего кода, присущего макросам препроцессора, но при этом нет опасности не верной расстановки скобок.