Обратные вызовы в C++ | страница 21
2.4.6. Производительность
С точки зрения машинных команд, вызов функции – не слишком быстрая операция. Необходимо несколько команд для сохранения стека10; команда перехода к коду функции; команда возврата управления; несколько команд для восстановления стека. А если код тела функции небольшой, к примеру, всего лишь сравнение двух величин, то время, затраченное на вызов функции, может значительно превысить время выполнения кода функции.
Поясним сказанное на примере. Напишем маленькую простую программу, которая считывает из консоли два числа, складывает их и результат выводит на экран (Листинг 19).
>#include
>int Calculate(int a, int b)
>{
> return a + b;
>}
>int main()
>{
> int a, b;
> std::cin >> a >> b;
> int result = Calculate(a, b);
> std::cout << result;
>}
Откомпилируем код с выключенной оптимизацией и запустим на выполнение. Посмотрим дизассемблерный участок кода 11, в котором производится вызов функции (Листинг 20):
>int Calculate(int a, int b)
>{
>00007FF6DA741005 and al,8 // 1
>return a + b;
>00007FF6DA741008 mov eax,dword ptr [b] // 2
>00007FF6DA74100C mov ecx,dword ptr [a] // 3
>00007FF6DA741010 add ecx,eax // 4
>00007FF6DA741012 mov eax,ecx // 5
>}
>00007FF6DA741014 ret // 6
>int main()
>{
>…….
>int result = Calculate(a, b);
>00007FF6DA741053 mov edx,dword ptr [b] // 7
>00007FF6DA741057 mov ecx,dword ptr [a] // 8
>00007FF6DA74105B call Calculate (07FF6DA741000h) // 9
>00007FF6DA741060 mov dword ptr [result],eax // 10
>…….
В строках 7 и 8 введенные значения a и b сохраняются в регистрах. В строке 9 выполняется вызов функции. В строке 1 выполняется обнуление результата, в строках 2 и 3 переданные значения копируются в регистры, в строке 4 выполняется сложение, в строке 5 результат копируется обратно в регистр, в строке 6 выполняется выход из функции, в строке 10 результат вычисления функции копируется в переменную результата.
Теперь включим оптимизацию, откомпилируем и посмотрим на код (Листинг 21):
>int main()
>{
>…….
>int result = Calculate(a, b);
>00007FF7D5B11033 mov edx,dword ptr [b]
>00007FF7D5B11037 add edx,dword ptr [a]
Как видим, для вычислений у нас всего две операции: запись в регистр значения b и добавление к нему значения a. Код встроен в поток выполнения, вызов функции не производится. Ощутимая разница, не правда ли?