क्यों argc एक स्थिर नहीं है?


104
int main( const int argc , const char[] const argv)

जैसा कि प्रभावी C ++ आइटम # 3 बताता है कि "जब भी संभव हो तो कास्ट का उपयोग करें", मैं सोचने लगता हूं कि "इन 'स्थिर' मापदंडों को क्यों नहीं बनाया जाए const"।

क्या कोई ऐसा परिदृश्य है जिसमें मूल्य argc किसी कार्यक्रम में को संशोधित किया गया है?


38
आप के argcरूप में घोषित करने के लिए स्वतंत्र हैं const
ओलिवर चार्ल्सवर्थ

14
मैंने कई उत्पादन गुणवत्ता कोड देखे हैं जो ऐसा करते हैं:--argc
अनिकेत इंग

2
मुझे लगता है कि यह सी विरासत के साथ करना है, लेकिन पता नहीं कैसे होगा।
लुइस माचूका

13
मुझे संदेह है कि "जब भी संभव हो तो कास्ट का उपयोग करें" संदर्भ द्वारा पारित चीजों को संदर्भित करता है, जहां फ़ंक्शन के बाहर आने के बाद फ़ंक्शन के भीतर कोई भी संशोधन जारी रहता है। यह पूर्णांक की तरह मूल्य से पारित चीजों के साथ सच नहीं है, इसलिए इसे बनाने से कुछ हासिल नहीं होता है const; वास्तव में, argcएक ऐसे const intसाधन के रूप में गुजरना जो आप तब उपयोग नहीं कर सकते argc, जैसे कि, फ़ंक्शन के अंदर एक काउंटर।
स्टीव मेलनिकॉफ़

4
@SteveMelnikoff: मैं इस बात से सहमत नहीं हूं कि constपास-बाय-वैल्यू पैरामीटर बनाकर कुछ हासिल नहीं करना है । उदाहरण के लिए देखें stackoverflow.com/a/8714278/277304 और stackoverflow.com/a/117557/277304
leonbloy

जवाबों:


114

इस मामले में, इतिहास एक कारक है। C ने इन इनपुट को "निरंतर नहीं" के रूप में परिभाषित किया, और मौजूदा सी कोड के साथ (अच्छे भाग के साथ) संगतता C ++ का प्रारंभिक लक्ष्य था।

कुछ यूनिक्स एपीआई, जैसे getopt, वास्तव में हेरफेर करते हैं argv[], इसलिए इसे constउस कारण से भी नहीं बनाया जा सकता है ।

(इसके अलावा: दिलचस्प है, हालांकि getoptप्रोटोटाइप का सुझाव है कि यह संशोधित नहीं होगा, argv[]लेकिन इंगित किए गए तारों को संशोधित कर सकता है, लिनक्स मैन पेज इंगित करता है कि getoptइसके तर्कों को अनुमति देता है, और ऐसा लगता है कि वे जानते हैं कि वे शरारती हैं । ओपन में मैन पेज। समूह इस क्रमांकन का उल्लेख नहीं करता है।)

लाना constपर argcऔर argvज्यादा खरीद नहीं होता है और यह प्रोग्रामिंग जैसे प्रथाओं, कुछ पुराने स्कूल को अमान्य होगा:

// print out all the arguments:
while (--argc)
    std::cout << *++argv << std::endl;

मैंने C में ऐसे कार्यक्रम लिखे हैं, और मुझे पता है कि मैं अकेला नहीं हूँ। मैंने कहीं से उदाहरण की नकल की ।


1
-1 रे "कुछ यूनिक्स APIs, जैसे गेटअप, वास्तव में argv [] को मैनिपुलेट करते हैं, इसलिए इसे उस कारण के लिए भी कॉन्स्टेबल नहीं बनाया जा सकता है।" एक स्वतंत्र रूप से एक शीर्ष स्तर जोड़ सकते हैं constकरने के लिए argvकिसी भी सी समारोह क्या कर सकते हैं को प्रभावित किए बिना,। साथ getoptही घोषित किया जाता है int getopt(int argc, char * const argv[], const char *optstring);। और यहाँ constशीर्ष स्तर नहीं है, लेकिन संकेतकर्ताओं को घोषित करता है const, उन्हें संशोधित नहीं करने का वादा किया जाता है (हालांकि वे जो संकेत देते हैं कि वे इंगित कर सकते हैं कि संभवतः संशोधित किया जा सकता है)।
चीयर्स एंड हीथ। - अल्फ

@ Cheersandhth.-Alf: getopt permutesargv[] डिफ़ॉल्ट रूप से सरणी, लेकिन तार संशोधित नहीं करता है। (शब्द परमिट सीधे मैन पेज से आता है।) इसका मतलब यह है कि argvसरणी खुद भी नहीं है, constभले ही तार यह इंगित करता है। कैसे argv[]सरणी को अनुमति दे रहा है इसे हेरफेर नहीं कर रहा है?
जो जेड

1
मुझे क्षमा करें, जिन डॉक्स को मैंने देखा, वे असंगत हैं: हस्ताक्षर इस तरह के परमिट की अनुमति नहीं देते हैं। उदाहरण देखें । हालाँकि, निम्न पाठ कहता है कि यह अनुमति देता है। तो, मैं नीचे हटा रहा हूँ।
चीयर्स एंड हीथ। - अल्फ

1
यही है, आपको "अनलॉक" करने के लिए कुछ संपादन करना होगा ताकि मैं डाउनवोट को हटा सकूं। और नहीं, आप प्रोटोटाइप को गलत समझ रहे हैं। मेरे द्वारा दिए गए उदाहरण और संकलन त्रुटि, "केवल पढ़ने के स्थान का असाइनमेंट" देखें।
चीयर्स एंड हीथ। - अल्फ

1
@ Cheersandhth.-Alf: यह दिलचस्प है ... मैंने हेडर में प्रोटोटाइप को देखा, और यह char* const* ___argvवहां है, लेकिन इंटरफ़ेस वास्तव में पालन करता है const char **। ऐसी उलझन। मैंने []और की पूर्वता को भ्रमित कर दिया था* संबंध दिया था const। मैं क्षमाप्रार्थी हूं।
जो जेड

36

C मानक (ISO / IEC 9899: 2011) कहता है:

5.1.2.2.1 प्रोग्राम स्टार्टअप

¶1 प्रोग्राम स्टार्टअप पर कहा जाने वाला फ़ंक्शन नाम है main। कार्यान्वयन इस फ़ंक्शन के लिए कोई प्रोटोटाइप घोषित नहीं करता है। इसे इंट के रिटर्न प्रकार और बिना किसी पैरामीटर के साथ परिभाषित किया जाएगा:

int main(void) { /* ... */ }

या दो मापदंडों के साथ (यहाँ करने के लिए भेजा के रूप में argcऔर argv, हालांकि किसी भी नाम का इस्तेमाल किया जा सकता है, वे समारोह में वे घोषित किये गए हैं करने के लिए स्थानीय कर रहे हैं के रूप में):

int main(int argc, char *argv[]) { /* ... */ }

या उसके बराबर; 10) या कुछ अन्य कार्यान्वयन-परिभाषित तरीके से।

¶2 यदि वे घोषित किए जाते हैं, तो mainफ़ंक्शन के पैरामीटर निम्नलिखित बाधाओं का पालन करेंगे:

  • का मूल्य argcnonnegative होगा।
  • argv[argc] एक अशक्त सूचक होगा।
  • यदि मान argcशून्य से अधिक है, तो सरणी सदस्य इसके argv[0]माध्यम से argv[argc-1] समावेशी के स्ट्रिंगर्स के लिए पॉइंटर्स होंगे, जिन्हें प्रोग्राम स्टार्टअप से पहले होस्ट वातावरण द्वारा कार्यान्वयन-परिभाषित मान दिए गए हैं। इरादा मेजबान वातावरण में कहीं और से कार्यक्रम स्टार्टअप से पहले निर्धारित कार्यक्रम की जानकारी की आपूर्ति करने के लिए है। यदि मेजबान वातावरण अपरकेस और लोअरकेस दोनों में अक्षरों के साथ तार की आपूर्ति करने में सक्षम नहीं है, तो कार्यान्वयन यह सुनिश्चित करेगा कि तार लोअरकेस में प्राप्त किए जाते हैं।
  • यदि का मान argc शून्य से अधिक है, तो इसके द्वारा इंगित स्ट्रिंग argv[0] प्रोग्राम के नाम का प्रतिनिधित्व करती है; argv[0][0]यदि प्रोग्राम नाम होस्ट वातावरण से उपलब्ध नहीं है, तो अशक्त वर्ण होगा। यदि का मान argcएक से अधिक है, तार द्वारा की ओर इशारा किया argv[1]के माध्यम से argv[argc-1] कार्यक्रम मापदंडों प्रतिनिधित्व करते हैं।
  • मापदंडों argcसरणी argvद्वारा इंगित किए गए और तार argvप्रोग्राम द्वारा संशोधित किए जाएंगे, और प्रोग्राम स्टार्टअप और प्रोग्राम समाप्ति के बीच अपने अंतिम-संग्रहीत मानों को बनाए रखेंगे।

10) इस प्रकार, के intरूप में परिभाषित टाइपसेफ नाम से प्रतिस्थापित किया जा सकता है int, या इस प्रकार argvलिखा जा सकता है char **argv, और इसी तरह।

अंतिम बुलेट बिंदु पर ध्यान दें। यह कहता है कि दोनों argcऔरargv परिवर्तनीय होना चाहिए। उन्हें संशोधित करने की आवश्यकता नहीं है, लेकिन उन्हें संशोधित किया जा सकता है।


दिलचस्प। एक अर्ध-संबंधित नोट पर, मैं एक दुर्घटनाग्रस्त बग में भाग गया, जो निकला क्योंकि क्यूटी के QApplication(argc,argv)निर्माता को argcसंदर्भ के साथ परिभाषित किया गया था । जिसने मुझे चौंका दिया।
HostileFork का कहना है कि

23

argcआम तौर पर एक स्थिर नहीं है क्योंकि main()पूर्व तारीखों के लिए फ़ंक्शन हस्ताक्षर const

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

आप निश्चित रूप से, constयदि आप चाहें तो इसे घोषित करने के लिए स्वतंत्र हैं।


8

एक constऔपचारिक तर्क पर एक शीर्ष स्तर फ़ंक्शन प्रकार का हिस्सा नहीं है। आप इसे जोड़ सकते हैं या इसे अपनी इच्छानुसार हटा सकते हैं: यह केवल वही प्रभावित करता है जो आप फ़ंक्शन कार्यान्वयन में तर्क के साथ कर सकते हैं।

तो argcआप के लिए स्वतंत्र रूप से जोड़ सकते हैं एक const

लेकिन argvआप constबिना फंक्शन के सिग्नेचर को बदले बिना कैरेक्टर डेटा नहीं बना सकते । जिसका अर्थ है कि यह तब मानक mainफ़ंक्शन हस्ताक्षरों में से एक नहीं है, और इसे mainफ़ंक्शन के रूप में मान्यता नहीं दी जाएगी । तो, एक अच्छा विचार नहीं है।


mainगैर-टॉय कार्यक्रमों में मानक तर्कों का उपयोग नहीं करने का एक अच्छा कारण यह है कि विंडोज में वे अंतरराष्ट्रीय पात्रों के साथ फ़ाइलनाम जैसे वास्तविक कार्यक्रम तर्कों का प्रतिनिधित्व करने में सक्षम नहीं हैं। ऐसा इसलिए है क्योंकि विंडोज में वे बहुत मजबूत कन्वेंशन द्वारा विंडोज एएनएसआई के रूप में एन्कोडेड हैं। विंडोज में आप GetCommandLineएपीआई फ़ंक्शन के संदर्भ में कुछ और पोर्टेबल तर्क एक्सेस सुविधा को लागू कर सकते हैं ।


जोड़ने से संक्षेप, कुछ भी नहीं रोकता है आप constके लिए argcहै, लेकिन सबसे अधिक उपयोगी constपर -नेस argvआप एक गैर मानक देना होगा mainसमारोह, सबसे शायद रूप में मान्यता नहीं। खुशी से (एक विडंबनापूर्ण तरीके से) पोर्टेबल गंभीर कोड के लिए मानक तर्कों का उपयोग नहीं करने के लिए अच्छे कारण हैं main। काफी बस, इन-प्रैक्टिस के लिए वे केवल पुराने ASCII का समर्थन करते हैं, केवल अंग्रेजी वर्णमाला अक्षरों के साथ।


1
यदि आप साइबर के साथ विंडोज के लिए विकसित कर रहे हैं या एक और लिबास है जो ठीक से यूटीएफ -8 का समर्थन करता है (जहां तक ​​मुझे पता है, वर्तमान में केवल एक ही है, लेकिन मैं किसी दूसरे विकल्प पर काम कर रहा हूं), मानक mainहस्ताक्षर ठीक काम करता है और आप कर सकते हैं मनमाना यूनिकोड तर्क प्राप्त करें।
आर .. गिटहब स्टॉप हेल्पिंग ICE

@R वे ज्यादातर * निक्स प्लेटफॉर्म पर भी ठीक काम करते हैं। मुद्दा यह नहीं है कि क्या ऐसे प्लेटफार्म हैं जहां वे काम करते हैं। लेकिन, बहुत अच्छी पहल , और जैसा कि होता है कि मैं भी यही कर रहा हूं, कम या ज्यादा गंभीरता से
चीयर्स और हीथ। - अल्फ

4

का हस्ताक्षर mainकुछ हद तक एक ऐतिहासिक कलाकृति से है C। ऐतिहासिक रूप Cसे नहीं था const

हालाँकि, आप अपने पैरामीटर की घोषणा कर सकते हैं constक्योंकि कास्ट का प्रभाव केवल संकलन समय है।


जब आप "ऐतिहासिक सी" कहते हैं, तो हम यहां कैसे ऐतिहासिक बात कर रहे हैं?
जो जेड

8
constC89 / C90 में जोड़ा गया था; इससे पहले, यह सी। का हिस्सा नहीं था
जोनाथन लेफ़लर

@JonathanLeffler: आप जानते हैं, मैं यह भूल गया था। मैंने 1992 में सी सीखा। इससे पहले मैं पास्कल, बेसिक और असेंबली हैकर था।
जो जेड

2

क्योंकि argcएक स्थानीय चर है (और, सी ++ में, एक संदर्भ या कुछ नहीं), और क्योंकि mainइसका मतलब है कि पीछे की संगतता के शेननिगेंस ने इसे बाध्य करने के लिए अनुप्रयोगों को मजबूर करने के लिए कोई बाध्यकारी कारण के साथ भारी मात्रा में अनुदान दिया ।

main() {}

int main() {}

main() { return 0; }

main(int argc, char* argv[]) { return 0; }

int main(const int argc, const char** argv) { /* no return*/ }

ये और कई अन्य विविधताएँ C और C ++ कंपाइलरों की एक विस्तृत श्रृंखला को संकलित करेंगी।

तो अंतत: ऐसा नहीं है कि argc const नहीं है, बस यह होना जरूरी नहीं है, लेकिन यह हो सकता है कि आप इसे चाहते हैं।

http://ideone.com/FKldHF , C उदाहरण:

main(const int argc, const char* argv[]) { return 0; }

http://ideone.com/m1qc9c , C ++ उदाहरण

main(const int argc) {}

ध्यान दें कि स्पष्ट रिटर्न प्रकार के बिना वेरिएंट अब C99 में मान्य नहीं हैं, अकेले C11 को दें, हालांकि कंपाइलर उन्हें पीछे की संगतता के कारणों के लिए अनुमति देते हैं। C ++ कंपाइलर को रिटर्न प्रकार के बिना वेरिएंट को स्वीकार नहीं करना चाहिए।
जोनाथन लेफलर

@JonathanLeffler हां, फिर भी अंतिम विचारधारा का उदाहरण ( ideone.com/m1qc9c ) G ++ 4.8.2 है -std=c++11। क्लैंग भी इसे स्वीकार करता है, लेकिन देता है warning: only one parameter on 'main' declaration [-Wmain], और एमएसवीसी केवल लापता रिटर्न प्रकार के बारे में विरोध करता है और argc के संदर्भ का अभाव है। फिर, '
शेंनिगन्स

1

ऐतिहासिक कारणों के अलावा, argc और argv को गैर रखने का एक अच्छा कारण-const यह है कि संकलक कार्यान्वयन को पता नहीं है कि आप मुख्य के तर्कों के साथ क्या करने जा रहे हैं, यह सिर्फ यह जानता है कि यह आपको उन तर्कों को देना होगा।

जब आप अपने स्वयं के कार्यों और संबंधित प्रोटोटाइप को परिभाषित कर रहे हैं, तो आप जानते हैं कि आप कौन से पैरामीटर बना सकते हैं const और कौन से आपके फ़ंक्शन को संशोधित करेंगे।

एक चरम पर ले जाया गया, आप घोषणा कर सकते हैं कि सभी कार्यों के सभी मापदंडों को घोषित किया जाना चाहिए const, और फिर यदि आपके पास उन्हें बदलने का कारण है (उदाहरण के लिए एक सरणी के माध्यम से खोज करने के लिए एक सूचकांक में वृद्धि), तो आपको स्थानीय गैर- constचर बनाना होगा और constउन चरों में तर्कों के मूल्यों की प्रतिलिपि बनाएँ । यह व्यस्त काम और बिना किसी वास्तविक लाभ के अतिरिक्त LOC के लिए बनाता है। यदि आप किसी तर्क के मूल्य को संशोधित नहीं कर रहे हैं, और अनुशंसा करते हैं कि आप पैरामीटर बनाते हैं तो एक सभ्य स्थिर विश्लेषक उठाएगा const

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.