Odpowiedzi:
Makra preprocesora to po prostu wzorce podstawiania stosowane w kodzie. Mogą być używane prawie w każdym miejscu w kodzie, ponieważ są zastępowane ich rozszerzeniami przed rozpoczęciem jakiejkolwiek kompilacji.
Funkcje wbudowane to rzeczywiste funkcje, których treść jest bezpośrednio umieszczana w witrynie wywołania. Można ich używać tylko wtedy, gdy wywołanie funkcji jest odpowiednie.
Teraz, jeśli chodzi o używanie makr i funkcji wbudowanych w kontekście podobnym do funkcji, pamiętaj, że:
Po pierwsze, makra preprocesora są po prostu „kopiuj wklej” w kodzie przed kompilacją. Nie ma więc sprawdzania typu i mogą pojawić się pewne efekty uboczne
Na przykład, jeśli chcesz porównać 2 wartości:
#define max(a,b) ((a<b)?b:a)
Efekty uboczne pojawiają się, jeśli używasz max(a++,b++)
na przykład ( a
lubb
zostaną zwiększone dwukrotnie). Zamiast tego użyj (na przykład)
inline int max( int a, int b) { return ((a<b)?b:a); }
max(fibonacci(100), factorial(10000))
weź pod uwagę, że większe zostanie obliczone dwukrotnie :(
Funkcje Inline są rozszerzane przez kompilator, gdzie makra są rozszerzane przez Preprocessor, który jest zwykłym podstawieniem tekstowym.
Nie ma sprawdzania typów podczas wywoływania makra, podczas gdy sprawdzanie typów jest wykonywane podczas wywołania funkcji.
Niepożądane wyniki i nieefektywność mogą wystąpić podczas ekspansji makr z powodu ponownej oceny argumentów i kolejności operacji. Na przykład
#define MAX(a,b) ((a)>(b) ? (a) : (b))
int i = 5, j = MAX(i++, 0);
spowoduje
int i = 5, j = ((i++)>(0) ? (i++) : (0));
Argumenty makr nie są oceniane przed rozwinięciem makra
#define MUL(a, b) a*b
int main()
{
// The macro is expended as 2 + 3 * 3 + 5, not as 5*8
printf("%d", MUL(2+3, 3+5));
return 0;
}
// Output: 16`
Słowa kluczowego return nie można używać w makrach do zwracania wartości, jak w przypadku funkcji.
Funkcje wbudowane mogą być przeciążone
Tokeny przekazane do makr można łączyć za pomocą operatora ## zwanego operatorem Token-Pasting.
Makra są zwykle używane do ponownego wykorzystania kodu, gdzie funkcje wbudowane są używane do wyeliminowania narzutu czasu (nadmiaru czasu) podczas wywołania funkcji (unikanie skoku do podprogramu).
Kluczową różnicą jest sprawdzanie typu. Kompilator sprawdzi, czy to, co przekazujesz jako wartości wejściowe, jest typu, który można przekazać do funkcji. Nie jest to prawdą w przypadku makr preprocesora - są one rozwijane przed jakimkolwiek sprawdzaniem typu i mogą powodować poważne i trudne do wykrycia błędy.
Oto kilka innych, mniej oczywistych punktów.
Aby dodać kolejną różnicę do już podanych: nie możesz przejść przez a #define
w debugerze, ale możesz przejść przez funkcję wbudowaną.
Makra ignorują przestrzenie nazw. I to czyni ich złymi.
Funkcje wbudowane są podobne do makr (ponieważ kod funkcji jest rozwijany w momencie wywołania w czasie kompilacji), funkcje wbudowane są analizowane przez kompilator, podczas gdy makra są rozszerzane przez preprocesor. W rezultacie istnieje kilka ważnych różnic:
W niektórych przypadkach wyrażenia przekazane jako argumenty do makr mogą być oceniane więcej niż raz. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx
makra są rozwijane przed kompilacją, nie można ich używać do debugowania, ale można używać funkcji wbudowanych.
- dobry artykuł : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1
;
Funkcja inline zachowa semantykę wartości, podczas gdy makro preprocesora po prostu kopiuje składnię. Możesz uzyskać bardzo subtelne błędy z makrem preprocesora, jeśli użyjesz argumentu wiele razy - na przykład, jeśli argument zawiera mutację typu „i ++”, wykonanie tego dwukrotnego wykonania jest sporym zaskoczeniem. Funkcja inline nie będzie miała tego problemu.
Funkcja wbudowana zachowuje się składniowo tak jak normalna funkcja, zapewniając bezpieczeństwo typów i zakres dla lokalnych zmiennych funkcji oraz dostęp do elementów składowych klasy, jeśli jest to metoda. Również podczas wywoływania metod wbudowanych należy przestrzegać ograniczeń prywatnych / chronionych.
Aby poznać różnicę między makrem a funkcją inline , najpierw powinniśmy wiedzieć, czym dokładnie są i kiedy powinniśmy ich używać.
FUNKCJE :
int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
Z wywołaniami funkcji wiąże się narzut, ponieważ po zakończeniu wykonywania funkcji musi wiedzieć, dokąd ma zwrócić, a także musi przechowywać wartość w pamięci stosu.
W przypadku małych aplikacji nie będzie to problem, ale weźmy przykład aplikacji finansowych, w których tysiące transakcji odbywają się co sekundę, nie możemy iść z wywołaniami funkcji.
MAKRA:
# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
int wynik = Kwadrat (x * x)
Ale makra mają związane z tym błędy.
#define Square(x) x*x
int main() {
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Tutaj wynik wynosi 11, a nie 36 .
FUNKCJE INLINE :
inline int Square(int x) {
return x * x;
}
int main() {
using namespace std;
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Wyjście 36
Słowo kluczowe Inline żąda od kompilatora zastąpienia wywołania funkcji treścią funkcji, w tym przypadku dane wyjściowe są poprawne, ponieważ najpierw ocenia wyrażenie, a następnie są przekazywane. Zmniejsza obciążenie wywołania funkcji, ponieważ nie ma potrzeby przechowywania adresu zwrotnego i stosu pamięć nie jest wymagana dla argumentów funkcji.
Porównanie makr i funkcji wbudowanych:
WNIOSEK:
Funkcje wbudowane są czasami bardziej przydatne niż makra, ponieważ poprawiają wydajność i są bezpieczne w użyciu, a także zmniejszają narzut wywołań funkcji. To tylko żądanie do kompilatora, niektóre funkcje nie będą wbudowane, jak:
co jest dobrą rzeczą, ponieważ wtedy kompilator uważa, że najlepiej zrobić coś w inny sposób.
W GCC (nie jestem pewien co do innych) deklarowanie funkcji w linii jest tylko wskazówką dla kompilatora. Nadal do kompilatora na koniec dnia należy decyzja, czy zawiera on treść funkcji przy każdym wywołaniu.
Różnica między funkcjami wbudowanymi a makrami preprocesora jest stosunkowo duża. Makra preprocesora pod koniec dnia zastępują tylko tekst. Zrezygnowałeś w dużej mierze z możliwości kompilatora do sprawdzania sprawdzania typów argumentów i zwracanego typu. Ocena argumentów jest zupełnie inna (jeśli wyrażenia, które przekazujesz do funkcji, mają skutki uboczne, debugowanie będzie bardzo przyjemne). Istnieją subtelne różnice w miejscach, w których można używać funkcji i makr. Na przykład gdybym miał:
#define MACRO_FUNC(X) ...
Gdzie MACRO_FUNC oczywiście definiuje treść funkcji. Należy zachować szczególną ostrożność, aby działała poprawnie we wszystkich przypadkach, w których można użyć funkcji, na przykład źle napisana funkcja MACRO_FUNC spowodowałaby błąd w
if(MACRO_FUNC(y)) {
...body
}
Można tam bez problemu użyć normalnej funkcji.
Z punktu widzenia kodowania funkcja inline jest podobna do funkcji. Zatem różnice między funkcją wbudowaną a makrem są takie same, jak różnice między funkcją a makrem.
Z punktu widzenia kompilacji funkcja inline jest podobna do makra. Jest wstrzykiwany bezpośrednio do kodu, a nie wywoływany.
Ogólnie rzecz biorąc, powinieneś traktować funkcje wbudowane jako zwykłe funkcje z pewnymi pomniejszymi optymalizacjami. I podobnie jak w przypadku większości optymalizacji, kompilator decyduje, czy rzeczywiście chce je zastosować. Często kompilator z radością ignoruje wszelkie próby wbudowania funkcji przez programistę z różnych powodów.
Funkcje wbudowane będą zachowywać się jak wywołanie funkcji, jeśli istnieje w nich jakakolwiek instrukcja iteracyjna lub rekurencyjna, aby zapobiec powtarzaniu się instrukcji. Bardzo pomocne jest zachowanie ogólnej pamięci programu.
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{
return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases.
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
return a*a*a;
}
int main()
{
cout<<NUMBER<<endl<<number()<<endl;
cout<<CUBE(1+3); //Unexpected output 10
cout<<endl<<cube(1+3);// As expected 64
return 0;
}
Makra są zwykle szybsze niż funkcje, ponieważ nie obejmują rzeczywistego obciążenia wywołania funkcji.
Niektóre wady makr: nie ma sprawdzania typu, trudne do debugowania, ponieważ powodują prostą zamianę, makra nie mają przestrzeni nazw, więc makro w jednej sekcji kodu może wpływać na inną sekcję. Makra mogą powodować efekty uboczne, jak pokazano w powyższym przykładzie CUBE ().
Makra to zwykle jedna linijka. Mogą jednak składać się z więcej niż jednej linii, więc w funkcjach nie ma takich ograniczeń.
#define TWO_N(n) 2 << n
wtedy cout << CUBE(TWO_N(3 + 1)) << endl;
? (Lepiej jest kończyć wiersze wyjścia, endl
niż nim zaczynać.)