2009-07-14 10 views
17

सी ++ फ़ंक्शंस में अंतिम पैरामीटर को अंतिम क्यों जोड़ा जाना चाहिए?सी ++ फ़ंक्शंस में अंतिम पैरामीटर को अंतिम क्यों जोड़ा जाना चाहिए?

+12

यह बेकार नहीं है। भाषा डिजाइन को समझना (और विशेष रूप से आपके द्वारा उपयोग की जाने वाली भाषा का डिज़ाइन) को आईएमओ को प्रोत्साहित किया जाना चाहिए। ऐसा करने के लिए, अन्य चीजों के साथ आपको यह पता लगाने की आवश्यकता है कि "स्पष्ट, सरल" सुधारों के लिए आपके विचार अव्यवहारिक क्यों हैं, अगर वे अव्यवहारिक हैं। और क्यों उस भाषा के डिजाइनरों को एक अवसर याद आया, अगर वे अव्यवहारिक नहीं हैं। मुझे यकीन है कि भाषा डिजाइन प्रोग्रामिंग से संबंधित है। –

उत्तर

26

भाषा परिभाषा को सरल बनाने और कोड को पढ़ने योग्य रखने के लिए।

void foo(int x = 2, int y); 

कि फोन और डिफ़ॉल्ट मान का लाभ लेने के लिए, आप इस तरह वाक्यविन्यास आवश्यकता होगी:

foo(, 3); 

कौन सा था शायद बहुत अजीब होने लगा। एक अन्य विकल्प तर्क सूची में नामों को निर्दिष्ट किया जाता है:

foo(y = 3); // assign 3 to y and then pass y to foo. 

नामकरण दृष्टिकोण पर विचार किया और आईएसओ समिति क्योंकि द्वारा अस्वीकार कर दिया गया था:

foo(y : 3); 

एक नया प्रतीक प्रयोग की जाने वाली यह पहले से ही कुछ का मतलब है क्योंकि होता वे फ़ंक्शन परिभाषा के बाहर पैरामीटर नामों के लिए एक नया महत्व पेश करने में असहज थे।

यदि आप अधिक सी ++ डिजाइन तर्कसंगतताओं में रुचि रखते हैं, तो Stroustrup द्वारा The Design and Evolution of C++ पढ़ें।

+1

हम foo (3) के बजाय foo (3) का उपयोग क्यों नहीं कर सकते? क्या कोई समस्या है जो कंपाइलर को प्रोग्रामर के इरादे को समझने से रोकती है? मुझे लगता है कि एक बेहतर कारण संकलन समय के दौरान अस्पष्टता के अवसर को कम करना और कंपाइलरों के निर्माण को आसान बनाना होगा। – user95319

+6

डी एंड ई में, स्ट्राउस्ट्रप का कहना है कि फंक्शन-घोषणा और कार्य-परिभाषा को अलग करने के कारण नाम-पैरामीटर मुहावरे सी ++ में मुश्किल है। यदि उपयोगकर्ता घोषणा में एक नाम का उपयोग करता है और कार्यान्वयन में दूसरा संकलक को संकलित करना होगा। – Abhay

+0

अभय - मुझे नहीं लगता कि वह कहता है - मुझे लगता है कि वह * रिपोर्ट * करता है कि समिति के कुछ लोगों ने सोचा और उनके कारण बताते हैं। हम सभी जानते हैं कि, स्ट्राउस्ट्रप घोषणा में नामों पर निर्भरता बनाने और परिभाषा को अनदेखा करने के साथ ठीक रहेगा (मेरे पास होगा)। –

19

आप निम्नलिखित समारोह को परिभाषित हैं:

void foo(int a, int b = 0, int c); 

आप समारोह कैसे फोन और एक और ग के लिए एक मूल्य की आपूर्ति, लेकिन डिफ़ॉल्ट रूप ख छोड़ना होगा?

foo(a = 10, c = 5); 

अगर यह संभव थे, तो डिफ़ॉल्ट तर्क:

foo(10, ??, 5); 

कुछ अन्य भाषाओं (जैसे, अजगर), समारोह तर्क सी/C++ के विपरीत निम्नलिखित की तरह नाम के योग्य नहीं किया जा सकता, सूची में कहीं भी हो सकता है।

+0

नीचे दिए गए मामलों के बारे में क्या है .. foo (int a, double b = 0.0, char c = 'a') – yesraaj

+0

वास्तव में, यदि संकलक पर्याप्त स्मार्ट है, तो हमें foo (10, 5) लिखने में सक्षम होना चाहिए। कंपाइलर को इसे foo (10, डिफ़ॉल्ट, 5) के रूप में समझना चाहिए। – user95319

+0

@raj: सी ++ में इसकी अनुमति है। आप इसके बारे में कुछ सोच सकते हैं, एक बार जब आप डिफ़ॉल्ट तर्क देना शुरू कर देते हैं तो आपको बीच में कुछ भी छोड़ दिए बिना अंत तक (यानी अंतिम पैरामीटर तक) देना होगा। – Naveen

5

कल्पना कीजिए कि आप इस प्रोटोटाइप के साथ एक समारोह था:

void testFunction(bool a = false, bool b = true, bool c); 

अब मान लीजिए कि मैं इस तरह समारोह कहा जाता है:

testFunction(true, false); 

कैसे संकलक जो पैरामीटर मैं आपूर्ति करने के लिए होती यह पता लगाने की अपेक्षा की जाती है के लिए मूल्य?

+0

यह पता लगाएगा क्योंकि उसके लिए नियम होंगे। उदाहरण के लिए, तर्क दूसरे और तीसरे पैरामीटर से बंधे होंगे। – juanchopanza

1

एक सामान्य नियम फ़ंक्शन पैरामीटर को कंपाइलर द्वारा संसाधित किया जाता है और दाएं से बाएं क्रम में स्टैक पर रखा जाता है। इसलिए यह समझ में आता है कि डिफ़ॉल्ट मान वाले किसी भी पैरामीटर का मूल्यांकन पहले किया जाना चाहिए।

(यह __cdecl पर लागू होता है, जो वीसी ++ और __stdcall फ़ंक्शन घोषणाओं के लिए डिफ़ॉल्ट होता है)।

+5

यह भाषा मानक द्वारा बिल्कुल निर्दिष्ट नहीं है, इसलिए यह भाषा का काम करने का कारण नहीं हो सकता है - ये चिंता के दो पूरी तरह से अलग स्तर हैं। –

+1

मैं स्वीकार करूंगा कि मुझे इसका एहसास नहीं हुआ, लेकिन मुझे पता है कि यह वीसी ++ और जीसीसी कंपाइलर्स का बहादुर है। – ChrisBD

1

इसकी वजह यह है कि यह तर्कों की सापेक्ष स्थिति का उपयोग करता है ताकि यह पता चल सके कि वे कौन से पैरामीटर हैं।

यह पहचानने के लिए प्रकारों का उपयोग कर सकता था कि एक वैकल्पिक पैरामीटर नहीं दिया गया था। लेकिन अंतर्निहित रूपांतरण इससे हस्तक्षेप कर सकता है। एक और समस्या प्रोग्रामिंग त्रुटियों होगी जो गलत तर्क त्रुटि के बजाय वैकल्पिक तर्क ड्रॉप आउट के रूप में व्याख्या की जा सकती है।

किसी भी तर्क को वैकल्पिक बनने की अनुमति देने के लिए, यह सुनिश्चित करने के लिए तर्कों की पहचान करने का एक तरीका होना चाहिए कि कोई प्रोग्रामिंग त्रुटि न हो या अस्पष्टताएं दूर न करें। यह कुछ भाषाओं में संभव है, लेकिन सी ++ में नहीं।

3

चूंकि अधिकांश उत्तरों बताते हैं कि पैरामीटर सूची में संभावित रूप से कहीं भी डिफ़ॉल्ट पैरामीटर होने से फ़ंक्शन कॉल की जटिलता और अस्पष्टता बढ़ जाती है (दोनों कंपाइलर और संभवतः फ़ंक्शन के उपयोगकर्ताओं के लिए अधिक महत्वपूर्ण)।

सी ++ के बारे में एक अच्छी बात यह है कि अक्सर आप जो चाहते हैं उसे करने का एक तरीका है (भले ही यह हमेशा एक अच्छा विचार न हो)। आप विभिन्न पैरामीटर पदों के लिए डिफ़ॉल्ट तर्क करना चाहते हैं, तो आप लगभग निश्चित रूप से भार के कि बस बिलकुल पलट गया और पूरी तरह से पैरामिट्रीकृत समारोह इनलाइन फोन लिख कर ऐसा कर सकते हैं:

int foo(int x, int y); 
int foo(int y) { 
    return foo(0, y); 
} 

और वहाँ आप के बराबर है:

int foo(int x = 0, int y); 
1

मानक समिति को विचार करने के लिए एक और चीज यह थी कि डिफ़ॉल्ट पैरामीटर अन्य सुविधाओं, जैसे अधिभारित फ़ंक्शंस, टेम्पलेट रिज़ॉल्यूशन और नाम लुकअप के साथ कैसे इंटरैक्ट करते हैं। ये सुविधाएं पहले से ही तरीकों का वर्णन करने के लिए बहुत जटिल और कठिन में बातचीत करती हैं। डिफ़ॉल्ट पैरामीटर बनाना कहीं भी दिखाई देने में सक्षम होगा केवल जटिलता को बढ़ाएगा।

0

यह कॉल सम्मेलन के बारे में एक बात है। कॉल कन्वेंशन: जब आप कोई फ़ंक्शन कॉल करते हैं, तो पैरामीटर को दाएं से बाएं से ढेर में धक्का दिया जाता है। उदा। , इसलिए एक ख ग यदि आप डिफ़ॉल्ट मान इस तरह बाएं से दाएं सेट:

fun(int a, int b, int c); 

ढेर इस तरह है

fun(int a = 1, int b = 2, int c); 

और इस तरह कहते हैं:

fun(4,5); 

आपकी कॉल का अर्थ है = 4, बी = 5, और सी = कोई मान नहीं; // क्या गलत है!

आप इस तरह समारोह घोषणा करते हैं:

fun(int a, int b = 2, int c = 3);

और इस तरह कहते हैं: fun(4, 5);

अपने कॉल एक = 4, ख = 5, और ग = डिफ़ॉल्ट मान सेट का मतलब है (3); // कौन सा सही है!

निष्कर्ष में, आपको डिफ़ॉल्ट मान दाएं से बाएं रखना चाहिए।

0

जिंग ज़ेंग सही है। मैं यहां अपनी टिप्पणियां जोड़ना चाहता हूं। जब एक फ़ंक्शन कहा जाता है, तो तर्क दाएं से बाएं से स्टैक पर धकेल दिए जाते हैं। उदाहरण के लिए, मान लें कि आपके पास यह मनमाने ढंग से कार्य है।

------ 
    b 
------ 
    a 
------ 
ret 
------ 
    c 
------ 

ऊपर यह चित्र इस कार्य के लिए स्टैक फ्रेम है:

int add(int a, int b) { 
    int c; 
    c = a + b; 
    return c; 
} 

यहाँ समारोह के लिए स्टैक फ्रेम है! जैसा कि आप देख सकते हैं, पहले बी को स्टैक पर धक्का दिया जाता है, फिर स्टैक पर धक्का दिया जाता है। उसके बाद फ़ंक्शन रिटर्न पता स्टैक पर धकेल दिया जाता है। फंक्शन रिटर्न पता मुख्य() में स्थान रखता है जहां से मूल रूप से फ़ंक्शन को बुलाया गया था, और फ़ंक्शन निष्पादित करने के बाद, प्रोग्राम का निष्पादन उस फ़ंक्शन के रिटर्न पते पर जाता है। फिर सी जैसे किसी स्थानीय चर को ढेर पर धकेल दिया जाता है।

अब मुख्य बात यह है कि तर्क दाएं से बाएं से स्टैक पर धकेल दिए जाते हैं। मूल रूप से आपूर्ति किए गए किसी भी डिफ़ॉल्ट पैरामीटर शब्दशः मान हैं, जो निष्पादन योग्य के कोड खंड में संग्रहीत होते हैं। जब प्रोग्राम निष्पादन किसी भी तर्क के बिना एक डिफ़ॉल्ट पैरामीटर का सामना करता है, तो यह उस शाब्दिक मान को स्टैक के शीर्ष पर धक्का देता है। फिर यह एक को देखता है और स्टैक के शीर्ष पर तर्क के मान को धक्का देता है। स्टैक पॉइंटर हमेशा आपके सबसे हाल ही में धक्का वाले चर के शीर्ष पर इंगित करता है। तो आपके द्वारा स्टैक पर धक्का देने वाले किसी भी शाब्दिक मान को डिफ़ॉल्ट पैरामीटर के रूप में "पीछे" स्टैक पॉइंटर के रूप में रखा जाता है।

कंपाइलर के लिए यह संभवतः पहले अधिक सटीक था कि पहले मनमाने ढंग से डिफ़ॉल्ट अक्षरशः मूल्यों को पहले स्टैक पर धक्का दें, क्योंकि वे स्मृति स्थान में संग्रहीत नहीं होते हैं, और ढेर को जल्दी से बनाते हैं। इस बारे में सोचें कि क्या होगा यदि चर को पहले ढेर पर धक्का दिया गया था, और फिर शाब्दिक। सीपीयू के लिए मेमोरी लोकेशन तक पहुंचने से सर्किट या सीपीयू रजिस्टर से शाब्दिक मूल्य खींचने की तुलना में अपेक्षाकृत लंबा समय लगता है। चूंकि स्टैक बनाम अक्षर पर चर को धक्का देने में अधिक समय लगता है, इसलिए शाब्दिकों को इंतजार करना होगा, फिर वापसी पते को इंतजार करना होगा, और स्थानीय चरों को भी इंतजार करना होगा। यह शायद दक्षता में एक बड़ी चिंता नहीं है, लेकिन यह सिर्फ मेरा सिद्धांत है कि डिफ़ॉल्ट तर्क हमेशा सी ++ में फ़ंक्शन हेडर की सही स्थिति में क्यों होते हैं। इसका मतलब है कि संकलक इस तरह से डिजाइन किया गया था।

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