Załóżmy że mamy taki program:
test.hpp
#ifndef __TEST_HPP__
#define __TEST_HPP__
enum oper_e
{
add,
sub,
mul,
div,
mod
}
int test( int a, int b, oper_e o );
#endif
test.cpp
#include "test.hpp"
int test( int a, int b, oper_e o )
{
int r;
switch( o )
{
case add: r = a + b; break;
case sub: r = a - b; break;
case mul: r = a * b; break;
case div: r = a / b; break;
case mod: r = a % b; break;
}
return r;
}
main.cpp
#include "test.hpp"
#include <iostream>
int main()
{
int a, b;
std::cin >> a;
std::cin >> b;
std::cout << test( a, b, add ) << std::endl;
std::cout << test( a, b, sub ) << std::endl;
std::cout << test( a, b, mul ) << std::endl;
std::cout << test( a, b, div ) << std::endl;
std::cout << test( a, b, mod ) << std::endl;
return 0;
}
Teraz pliki test.cpp i main.cpp kompilujemy osobno do pliku obiektowego.
W ten sposób kompilator podczas kompilacji main.cpp nie ma dostępu do wywoływanej funkcji więc nie może wykonać odpowiedniej optymalizacji bo funkcja test mogła by równie dobrze modyfikować zasoby zewnętrzne więc jest to owa „materializacja” się programu. Teraz dla prostej operacji dodawania, która mogła by być przetłumaczona na pojedynczą instrukcje procesora, zostanie wykonany szereg operacji najpierw przepisania argumentów do rejestrów, potem wywołania funkcji (zapisanie adresu powrotu i skoku), zapisanie ramki stosu na którą składa się kilka operacji, wykonania instrukcji warunkowych, wykonania działania, przywrócenie ramki stosu, powrotu z procedury (odczytanie adresu powrotu ze stosu i skok do niego). Zakłam że kompilator zoptymalizuje wewnątrz funkcje
test
.
Chodzi tu o to że używając bardzo rozbudowanych mechanizmów do prostych operacji kilkukrotnie może spowolnić czas działania danej części kodu. Bo przecież nigdy nie wiadomo co się kryje w zewnętrznym mechanizmie w nim mogą być kolejne wywołania i kolejne.
Sama biblioteka jest po to by ułatwić programistom życie i dla bardziej rozbudowanego kodu jest jak najbardziej wskazana, gdyż różnica w czasie działania może być nie znaczny, a czas na napisanie odpowiednich mechanizmów samemu może być nie opłacalne .
Pisząc własną bibliotekę C pod mój hobbistyczny OS przekonałem się ile naprawdę jest wewnętrznych zależności, a jest ich naprawdę wiele.
Dodam jeszcze że tak jak kompilator może zignorować
inline
to równie dobrze może je dodać w szczególności przy funkcjach zadeklarowanych jako
static
. A używanie tych słów kluczowych pomaga kompilatorowi w decyzji.
Należy również pamiętać że kompilator nie zrobi wszystkiego za nas, a im bardziej mu pomożemy tym lepszy będzie efekt końcowy.