सी (और सी ++) मानक पारित होने वाले तर्कों के क्रम को परिभाषित नहीं करता है, या स्मृति में उन्हें कैसे व्यवस्थित किया जाना चाहिए। यह किसी विशेष प्रोसेसर आर्किटेक्चर पर काम करने वाली किसी चीज़ के साथ आने के लिए कंपाइलर डेवलपर (आमतौर पर ओएस डेवलपर्स के साथ सहयोग में) पर निर्भर करता है।
अधिकांश आर्किटेक्चर में, स्टैक (और रजिस्ट्रार) का उपयोग किसी फ़ंक्शन में तर्क पारित करने के लिए किया जाता है, और फिर, अधिकांश आर्किटेक्चर के लिए, ढेर "उच्च से कम" पते से बढ़ता है, और अधिकांश सी कार्यान्वयन में, ऑर्डर का क्रम तर्क पारित किया जा रहा "पिछले छोड़ दिया" कर रहे हैं, इसलिए यदि हम एक समारोह
void test(int a, int b, int c)
तो तर्क क्रम में पारित कर रहे हैं है:
c, b, a
कार्य करने के लिए
।
हालांकि, यह जटिलता है जब तर्कों का मूल्य रजिस्टरों में पारित किया जाता है, और तर्क का उपयोग कर कोड उन तर्कों का पता ले रहा है - रजिस्टरों के पास पते नहीं हैं, इसलिए आप पता नहीं ले सकते एक रजिस्टर चर के। इसलिए संकलक स्टैक पर पते को स्टोर करने के लिए कुछ कोड उत्पन्न करेगा [जहां से हम मूल्य के पते को स्थानीय रूप से फ़ंक्शन पर प्राप्त कर सकते हैं]। यह पूरी तरह से संकलक के फैसले पर निर्भर करता है जो यह आदेश देता है, और मुझे पूरा यकीन है कि यह वही है जो आप देख रहे हैं।
आप हमें आपके कोड लेने के लिए और बजना के माध्यम से इसे पारित, तो हम देखते हैं:
define void @test(i32 %a, i32 %b, i32 %c) #0 {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
store i32 %c, i32* %c.addr, align 4
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i32* %a.addr, i32* %b.addr, i32* %c.addr)
%add.ptr = getelementptr inbounds i32, i32* %b.addr, i64 -1
%0 = load i32, i32* %add.ptr, align 4
%add.ptr1 = getelementptr inbounds i32, i32* %b.addr, i64 1
%1 = load i32, i32* %add.ptr1, align 4
%call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0), i32 %0, i32 %1)
ret void
}
हालांकि यह पूरी तरह से तुच्छ को पढ़ने के लिए नहीं हो सकता है, आप की कसौटी-समारोह है पहली कुछ पंक्तियों देख सकते हैं:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
store i32 %c, i32* %c.addr, align 4
यह अनिवार्य रूप से ढेर (%alloca
) पर अंतरिक्ष पैदा कर रही है और चर a
, b
भंडारण, और उन स्थानों में c
।
भी कम आसान को पढ़ने के लिए कोडांतरक कोड जीसीसी जेनरेट करता है, लेकिन आप एक ऐसी ही बात यहाँ हो रहा देख सकते हैं:
subq $16, %rsp ; <-- "alloca" for 4 integers.
movl %edi, -4(%rbp) ; Store a, b and c.
movl %esi, -8(%rbp)
movl %edx, -12(%rbp)
leaq -12(%rbp), %rcx ; Take address of ...
leaq -8(%rbp), %rdx
leaq -4(%rbp), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf ; Call printf.
आप सोच रहे होंगे क्यों यह 4 पूर्णांकों के लिए अंतरिक्ष आवंटित - कि है, क्योंकि ढेर चाहिए हमेशा x86-64 में 16 बाइट्स के साथ गठबंधन किया जाना चाहिए।
संभव डुप्लिकेट: // stackoverflow।कॉम/प्रश्न/621542/कंपाइलर-एंड-तर्क-ऑर्डर-ऑफ-मूल्यांकन-इन-सी) – Steephen
@ स्टेफेन मूल्यांकन का आदेश, वास्तव में? – kravemir
@Miro यह कार्यान्वयन विशिष्ट है और संकलक – Steephen