2017-09-29 20 views
6

से वापसी मूल्य के दृश्यों के पीछे सी ++ में फ़ंक्शन से लौटने वाले मूल्यों के पीछे क्या है?फ़ंक्शन C++

मेरी समझ में जब भी func। रिटर्निंग एड्रेस और स्टैक फ्रेम कहा जाता है (स्थानीय चर के साथ, func के सम्मानित आदेश। तर्क और रजिस्ट्रार) को कॉल स्टैक पर धकेल दिया जाता है।

लेकिन क्या होता है जब मुठभेड़ों को निष्पादित करते समय राज्यमेन वापस आते हैं? जैसे

int a(int b){ 
    int c = b * 2; 
    return c; 
} 

वापसी कथन का सामना करने के बाद, सी के मूल्य EAX रजिस्टर में संग्रहीत, स्थानीय चर नष्ट कर रहे हैं और स्टैक फ्रेम कॉल स्टैक से निकाल दिया जाता है, और बाद EAX रजिस्टर में मूल्य "लौटने का पता" में ले जाया जाता है कि है याद?

या मैंने इस अवधारणा को गलत समझा?

सभी मदद की अत्यधिक सराहना की जाती है। धन्यवाद।

+0

कॉलिंग फ़ंक्शन केवल ईएक्स (या कहीं भी) – Caleth

+5

का उपयोग करेगा क्या आप जानना चाहते हैं कि अन-अनुकूलित केस में क्या होता है? मैं पूछता हूं क्योंकि एक अच्छा पर्याप्त संकलक 'int foo = a (2);' '4' के साथ सीधे 'foo' प्रारंभ करने में बदल सकता है। – NathanOliver

+2

फ़ंक्शन के लिए असेंबली भाषा आउटपुट करने के लिए अपने कंपाइलर को बताएं। –

उत्तर

4

बीटीडब्ल्यू, असेंबली भाषा प्रोसेसर निर्भर है। एआरएम प्रोसेसर में ईएक्स रजिस्टर नहीं है।

कंपाइलर के पास पैरामीटर पास करने और पैरामीटर लौटने के लिए मानक हो सकता है। कार्यों से मूल्यों को वापस करने की विधि कार्यान्वयन (कंपाइलर) पर निर्भर है। पर सभी मानक कंपाइलर नहीं हैं।

अनुकूलन-रहित कोड
संकलनकर्ता प्रोसेसर रजिस्टरों का लाभ लेने के डिजाइन किए हैं।

यदि वापसी मूल्य एक ही रजिस्टर में फिट बैठता है, तो एक मूल्य का मूल्य वापस करने के लिए उपयोग किया जाएगा। प्रोसेसर पर निर्भर करता है।

बड़ी वस्तुओं/मानों के लिए, कंपाइलर के पास दो विकल्प हैं: ऑब्जेक्ट को एकाधिक रजिस्टरों में वापस करें या मूल्य पर पॉइंटर लौटाएं। पॉइंटर स्टैक में एक इंडेक्स के रूप में सरल हो सकता है या पता जहां वह मान है।

अनुकूलित कोड
संकलक या एक साधारण प्रोसेसर अनुदेश के साथ अपने समारोह की जगह ले सकती भी कोड ड्रॉप। इस मामले में, कोई वापसी मूल्य नहीं है।

कंपाइलर आपके फ़ंक्शन को निरंतर मूल्यांकन कर सकता है और निरंतर निष्पादन योग्य कोड में रख सकता है; इस प्रकार कोई फ़ंक्शन कॉल या फ़ंक्शन रिटर्न की आवश्यकता नहीं होती है।

संकलक इनलाइन आपके फ़ंक्शन का निर्णय ले सकता है। इस मामले में, असाइनमेंट स्टेटमेंट के समान कोई वापसी मूल्य नहीं है। मूल्य या अन्य रजिस्टर को रखने के लिए एक अस्थायी चर का उपयोग किया जा सकता है।

और जानकारी
अधिक विस्तृत जानकारी के लिए, "कंपाइलर सिद्धांत" शोध करें। इस पर एक ड्रैगन के साथ एक अच्छी किताब है ...

+0

संभवतः आपके प्रोग्रामिंग जीवन में एकमात्र समय जहां "यहां ड्रेगन हो" एक अच्छी बात है। – user4581301

2

सी ++ कंप्यूटर मेमोरी के सैद्धांतिक मॉडल के खिलाफ संचालन के मामले में निर्दिष्ट है।

इसमें एक विशेषता भी है "as if" नियम के रूप में जाना जाता है।इसका मतलब है कि संकलक किसी भी कोड को पसंद कर सकता है, बशर्ते कि समग्र अवलोकन योग्य प्रभाव "जैसा है" आपके द्वारा लिखे गए कोड का शाब्दिक रूप से स्मृति मॉडल के खिलाफ संचालन में अनुवाद किया गया था।

unoptimised कोड में, कोडांतरक उत्पादन वास्तविकता बहुत संचालन के पास में है, कोड में व्यक्त के लिए उदाहरण जीसीसी अपने कार्य के लिए निम्न कोड का उत्पादन हो सकता है:

a(int):         # @a(int) 
     push rbp      
     mov  rbp, rsp     
     mov  dword ptr [rbp - 4], edi 
     mov  edi, dword ptr [rbp - 4] 
     shl  edi, 1 
     mov  dword ptr [rbp - 8], edi 
     mov  eax, dword ptr [rbp - 8] 
     pop  rbp 
     ret 

और निम्नलिखित बुला कोड दिया:

extern void foo(int x); 

int main() 
{ 
    foo(a(2)); 
} 

निम्नलिखित कोड का उत्पादन किया जा सकता है:

main:         # @main 
     push rbp 
     mov  rbp, rsp 
     mov  edi, 2 
     call a(int) 
     mov  edi, eax 
     call foo(int) 
     xor  eax, eax 
     pop  rbp 
     ret 

इस सरल कार्यक्रम में, कोड का अवलोकन प्रभाव यह है कि foo को मूल्य 4 के तर्क के साथ बुलाया जाएगा। a पर कॉल केवल एक अवलोकन दुष्प्रभाव है। यही है, यह वापसी मूल्य इसके इनपुट मूल्य को दोगुना कर देता है।

क्योंकि दिए गए मान foo में सीधे पारित कर दिया है और कहीं भी संग्रहीत नहीं है, हम कह सकते हैं कि a बुला के सभी दुष्प्रभाव पूरी तरह से foo के लिए एक कॉल द्वारा खपत होती है।

इसलिए, यदि एक कंपाइलर जानता है कि a क्या करता है, तो उसे कॉल करने के लिए कोड उत्पन्न करने की आवश्यकता नहीं है। यह foo पर कॉल किया जा सकता है, जैसा कि 'as if' को a(2) पर कॉल किया गया है।

इस प्रकार
main:         # @main 
     push rax 
     mov  edi, 4   # note: 'as if' a(2) 
     call foo(int) 
     xor  eax, eax 
     pop  rcx 
     ret 

(जीसीसी पर) इस मामले में a के कार्यान्वयन है::

दरअसल, अनुकूलन जोड़ने हमें इस देता है

a(int):         # @a(int) 
# 'as if' we created a variable and did some arithmetic, 
# stored the result and then returned the result 
     lea  eax, [rdi + rdi] 
     ret 
1

आप जिज्ञासा की अवधि में पूछ रहे हैं, तो @ थॉमस मैथ्यूज का जवाब बहुत अच्छा है ...

यदि आपके पास किसी विशिष्ट परिदृश्य के बारे में कोई प्रश्न है, तो आप इसे स्वयं जांचें और परिणाम देखें, असेंबली कोड पढ़ना चुनौतीपूर्ण है लेकिन नरक संतोषजनक है।

int func(int a, int b) 
{ 
    return a + b; 
} 

int main(int argc, char ** argv) 
{ 
    int a, b; 
    a = b = 100; 

    int c = func(a, b); 
} 

आप देख सकते हैं, इस के रूप में यह हो जाता है के रूप में सरल है (सुझाव:: जब वियोजन, printf से बचने की कोशिश के रूप में यह विधानसभा का एक बहुत कहते हैं

उदाहरण के लिए, मैं जीसीसी का उपयोग कर निम्न उदाहरण संकलित कोड)।

-ggdb साथ संकलित इतना है कि यह gdb साथ काम करते हैं, और gdb <application> का उपयोग कर चलाने के लिए आसान हो जाएगा, तो बस एक ब्रेकपाइंट अपने विधि के अंदर जोड़ने के लिए, यह मारा और आदेश disassemble को चलाने के लिए प्रतीक्षा करें। उत्पादन कुछ इस तरह दिखेगा:

Breakpoint 1, func (a=100, b=100) at program.cpp:3 
3   return a + b; 
(gdb) disas 
Dump of assembler code for function func(int, int): 
    0x00000000004004d6 <+0>:  push %rbp 
    0x00000000004004d7 <+1>:  mov %rsp,%rbp 
    0x00000000004004da <+4>:  mov %edi,-0x4(%rbp) 
    0x00000000004004dd <+7>:  mov %esi,-0x8(%rbp) 
=> 0x00000000004004e0 <+10>: mov -0x4(%rbp),%edx 
    0x00000000004004e3 <+13>: mov -0x8(%rbp),%eax 
    0x00000000004004e6 <+16>: add %edx,%eax 
    0x00000000004004e8 <+18>: pop %rbp 
    0x00000000004004e9 <+19>: retq 
End of assembler dump. 

आप देख सकते हैं, यहाँ केवल एक चीज संकलक करता RBP (pop %rbp) में वर्ष आधार सूचक पॉप और फिर वापस हमारे वापसी पता (retq) के लिए कूद है। परिणाम पहले से ही एक रजिस्टर में संग्रहीत है, इसलिए कुछ और करने में कोई ज़रूरत नहीं है।

संबंधित मुद्दे