funkcja inline nieco bardziej złożona

0

Mam takie pytanie: funkcja inline polega na tym, że zamiast wywoływania jej ciało zostaje wprowadzone do kodu.
Łatwo sobie to wyobrazić np. dla takiej funkcji:
inline add(int a, int b){return a+b;}
wówczas kod typu:
z = add(x,y);
w rzeczywistości wygląda tak:
z = x+y;

Mam jednak pytanie jak w takim razie wyglądałaby taka funkcja:
inline funkcja(double& x)
{
x = x*x;
double h1 = (1.0 - x); //jak ta nowa zmienna będzie wyglądać po wywołaniu tej funkcji?
double h2 = (1.0 + x);
return h1/h2;
}
//---
double x=5;
double z = funkcja(x); //jakby to wyglądało po kompilacji?

Przecież nie można zrobić czegoś takiego: double z = (x=x*x; double h1 = (1.0 - x); ... );

Z góry dziękuję za pomoc

0

disassemblery chyba z internetu ukradli.
Dopoki kompilator nie "oleje" Twoich zachcianek, to bedzie wygladalo to mniej wiecej tak jak ta funkcja.

0
KowalM napisał(a):

Przecież nie można zrobić czegoś takiego: double z = (x=x*x; double h1 = (1.0 - x); ... );

Owszem, ale można tak:

{
  double x2 = x;
  x2 = x2*x2;
  double h1 = (1.0 - x2); //jak ta nowa zmienna będzie wyglądać po wywołaniu tej funkcji?
  double h2 = (1.0 + x2);
  z=h1/h2;
}

Włącznie z nawiasami klamrowymi.

0

po pierwsze, kompilator może robić z kodem dowolne wygibasy, pod warunkiem że wynik jest ten sam.

dobry kompilator zrobi tak:

 double x=25;
 double z = -24.0/26;

nie traktuj inline jako dosłownego wklejenia kodu źródłowego z jednej funkcji w drugą. proces ten odbywa się na poziomie instrukcji asemblera, albo którejś fazy pośredniej kompilatora między źródłem a asemblerem.

0

Dziękuję bardzo za odpowiedzi! ;-)

0

dla niewiernego @n0name_l:

inline double funkcja(double& x)
{
    x = x*x;
    double h1 = (1.0 - x);
    double h2 = (1.0 + x);
    return h1/h2;
 }


int main()
{
   double x=5;
   double z = funkcja(x); //jakby to wyglądało po kompilacji?
}

kompilacja pod Visual Studio 2012 (z /Ox):

00241000  push        ebp  
00241001  mov         ebp,esp  
00241003  and         esp,0FFFFFFF8h  

00241006  xor         eax,eax  

00241008  mov         esp,ebp  
0024100A  pop         ebp  
0024100B  ret  

jest to tylko ramka stosu i return 0. poza tym cała funkcja i zmienne wyleciały jako nie mające żadnego znaczenia.

ale wyświetlmy wynik:

...
#include <iostream>
int main()
{
   double x=5;
   double z = funkcja(x); //jakby to wyglądało po kompilacji?
   std::cout << z;
}

teraz już kod ma wpływ na losy wszechświata, więc musi się wykonać.

01241220  push        ebp  
01241221  mov         ebp,esp  
01241223  and         esp,0FFFFFFC0h  

01241226  movsd       xmm0,mmword ptr ds:[1243228h]  
0124122E  mov         ecx,dword ptr ds:[1243030h]  
01241234  sub         esp,8  
01241237  movsd       mmword ptr [esp],xmm0  
0124123C  call        dword ptr ds:[1243038h]  

01241242  xor         eax,eax  
01241244  mov         esp,ebp  
01241246  pop         ebp  
01241247  ret

hmm, trochę to zagmatwane. jest ramka stosu, jakieś operacje na SSE, i skok do funkcji.
ale jeśli się przyjrzeć, to jest to w zasadzie tylko odczyt wartości z pamięci (movsd, mov).
czyżby więc?

#include <iostream>
int main()
{
   std::cout << -24.0/26.0;
}
00EC1220  movsd       xmm0,mmword ptr ds:[0EC3228h]  
00EC1228  mov         ecx,dword ptr ds:[0EC3030h]  
00EC122E  sub         esp,8  
00EC1231  movsd       mmword ptr [esp],xmm0  
00EC1236  call        dword ptr ds:[0EC3038h]  

00EC123C  xor         eax,eax  
00EC123E  ret

Ha! nagle nam zniknęła ramka stosu, ale istotne instrukcje są praktycznie takie same, tylko adresy się zmieniły.

więc TAK, kompilator zamienił całą funkcję, całe to double h2 = (1.0 + x); itd. na banalne wyświetlenie gotowej wartości.

1 użytkowników online, w tym zalogowanych: 0, gości: 1