सी में चर घोषणा प्लेसमेंट


129

मैंने लंबे समय से सोचा था कि सी में, फ़ंक्शन की शुरुआत में सभी चर घोषित किए जाने थे। मुझे पता है कि C99 में, नियम C ++ की तरह ही हैं, लेकिन C89 / ASI C के लिए चर घोषणा प्लेसमेंट नियम क्या हैं?

निम्नलिखित कोड सफलतापूर्वक gcc -std=c89और के साथ संकलित करता है gcc -ansi:

#include <stdio.h>
int main() {
    int i;
    for (i = 0; i < 10; i++) {
        char c = (i % 95) + 32;
        printf("%i: %c\n", i, c);
        char *s;
        s = "some string";
        puts(s);
    }
    return 0;
}

की घोषणाओं नहीं करना चाहिए cऔर sC89 / एएनएसआई मोड में त्रुटि आ जाती?


54
बस एक नोट: एएनसी सी में चर एक समारोह की शुरुआत में घोषित नहीं किया जाना चाहिए, बल्कि एक ब्लॉक की शुरुआत में। तो, आपके लिए लूप के शीर्ष पर चार सी = ... पूरी तरह से एएनसी सी में पूरी तरह से कानूनी है। हालांकि, चर * एस नहीं होगा।
जेसन कोको

जवाबों:


149

यह सफलतापूर्वक संकलित करता है क्योंकि GCC sएक GNU एक्सटेंशन के रूप में घोषित करने की अनुमति देता है , भले ही यह C89 या ANSI मानक का हिस्सा न हो। यदि आप उन मानकों का कड़ाई से पालन करना चाहते हैं, तो आपको पास होना चाहिए-pedantic ध्वज ।

cएक { }ब्लॉक की शुरुआत में घोषणा C89 मानक का हिस्सा है; ब्लॉक का कार्य नहीं होना चाहिए।


41
यह शायद ध्यान देने योग्य है कि केवल घोषणा ही sएक विस्तार है (C89 दृष्टिकोण से)। की घोषणा cC89 में पूरी तरह से कानूनी है, कोई एक्सटेंशन की आवश्यकता नहीं है।
अंटी

7
@AndreyT: हाँ, C में, चर घोषणाएं @ एक ब्लॉक की शुरुआत होनी चाहिए न कि एक फ़ंक्शन प्रति से; लेकिन लोग फ़ंक्शन के साथ ब्लॉक को भ्रमित करते हैं क्योंकि यह एक ब्लॉक का प्राथमिक उदाहरण है।
लीजेंड्स 2

1
मैंने जवाब में टिप्पणी को +39 वोटों के साथ स्थानांतरित कर दिया।
मर्कह

78

C89 के लिए, आपको अपने सभी चरों को एक स्कोप ब्लॉक की शुरुआत में घोषित करना होगा

तो, आपकी char cघोषणा वैध है क्योंकि यह लूप स्कोप ब्लॉक के लिए सबसे ऊपर है। लेकिन, char *sघोषणा में त्रुटि होनी चाहिए।


2
काफी सही। आप किसी भी {...} की शुरुआत में चर घोषित कर सकते हैं।
आर्टिलियस नोव

5
@ आर्टेलियस काफी सही नहीं है। केवल अगर कर्लियां एक ब्लॉक का हिस्सा हैं (न कि अगर वे एक संरचना या संघ की घोषणा या एक ब्रेडेड इनिशियलाइज़र का हिस्सा हैं)।
जेन्स

बस पांडित्यपूर्ण होने के लिए, गलत घोषणा को कम से कम सी मानक के अनुसार अधिसूचित किया जाना चाहिए। तो यह एक त्रुटि या एक चेतावनी होनी चाहिए gcc। यही है, विश्वास मत करो कि एक कार्यक्रम का मतलब यह हो सकता है कि यह आज्ञाकारी है।
जिनावी

35

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

सी ++ दुर्भाग्य से सी के साथ पिछड़े संगतता के लिए पुराने, शीर्ष घोषणा के तरीके को स्वीकार करता है (एक सी संगतता कई अन्य लोगों से बाहर खींचती है ...) लेकिन सी ++ इससे दूर जाने की कोशिश करती है:

  • C ++ सन्दर्भों का डिज़ाइन ब्लॉक ब्लॉकिंग के ऐसे शीर्ष की भी अनुमति नहीं देता है।
  • यदि आप एक सी ++ स्थानीय वस्तु की घोषणा और प्रारंभिककरण को अलग करते हैं तो आप कुछ भी नहीं के लिए एक अतिरिक्त निर्माणकर्ता की लागत का भुगतान करते हैं। यदि नो-आर्ग कंस्ट्रक्टर मौजूद नहीं है, तो फिर से आपको दोनों को अलग करने की भी अनुमति नहीं है!

C99 इसी दिशा में C को स्थानांतरित करना शुरू करता है।

यदि आप यह पता लगाने के लिए चिंतित नहीं हैं कि स्थानीय चर कहां घोषित किए गए हैं तो इसका मतलब है कि आपको बहुत बड़ी समस्या है: संलग्नक खंड बहुत लंबा है और इसे विभाजित किया जाना चाहिए।

https://wiki.sei.cmu.edu/confluence/display/c/DCL19-C.+Minimize+the+scope+of+variables+and+functions



यह भी देखें कि ब्लॉक के शीर्ष पर परिवर्तनशील घोषणाएं सुरक्षा छेद कैसे बना सकती हैं: lwn.net/Articles/443037
MarcH

"सी ++ दुर्भाग्य से सी के साथ पिछड़े संगतता के लिए पुराने, शीर्ष घोषणा के तरीके को स्वीकार करता रहता है": आईएमएचओ, यह करने के लिए सिर्फ साफ तरीका है। अन्य भाषा हमेशा 0. बज़्ट के साथ तुलना करके इस समस्या को "हल" करती है, यदि आप मुझसे पूछते हैं तो केवल तर्क त्रुटियां हैं। और ऐसे बहुत से मामले हैं जहाँ आपने आरंभीकरण के बिना घोषणा की है क्योंकि आरंभीकरण के लिए कई संभावित स्थान हैं। और यही कारण है कि C ++ का RAII वास्तव में बट में एक बहुत बड़ा दर्द है - अब आपको इन मामलों की अनुमति देने के लिए प्रत्येक ऑब्जेक्ट में एक "वैध" असंगठित राज्य को शामिल करने की आवश्यकता है।
जो सो

1
@JoSo: मैं उलझन में हूं कि आपको क्यों लगता है कि बिना पढ़े हुए वैरिएबल पैदावार के पैदावार से मनमाने ढंग से प्रभाव पड़ते हैं, जिससे प्रोग्रामिंग गलतियों का पता लगाने में आसानी होगी, बशर्ते कि वह एक सुसंगत मूल्य या नियतात्मक त्रुटि हो? ध्यान दें कि इस बात की कोई गारंटी नहीं है कि अनजाने में स्टोर किए गए स्टोरेज को पढ़ने वाला एक फैशन का व्यवहार करेगा, जो कि किसी भी बिट पैटर्न के अनुरूप हो सकता है, और न ही यह भी कि इस तरह का प्रोग्राम समय और कार्य-कारण के सामान्य नियमों के अनुरूप फैशन में व्यवहार करेगा। दिया कुछ इस तरह int y; ... if (x) { printf("X was true"); y=23;} return y;...
Supercat

1
@JoSo: पॉइंटर्स के लिए, विशेष रूप से कार्यान्वयन पर जो कि ट्रैप संचालन पर null, ऑल-बिट्स-शून्य अक्सर एक उपयोगी ट्रैप मूल्य है। इसके अलावा, उन भाषाओं में जो स्पष्ट रूप से निर्दिष्ट करती हैं कि चर सभी बिट्स-शून्य के लिए डिफ़ॉल्ट हैं, उस मूल्य पर निर्भरता एक त्रुटि नहीं है । कंपाइलर अभी तक अपने "ऑप्टिमाइज़ेशन" के साथ बहुत अधिक निराला नहीं हैं, लेकिन कंपाइलर लेखक अधिक से अधिक चतुर पाने की कोशिश करते रहते हैं। जानबूझकर छद्म-यादृच्छिक चर के साथ चर को आरंभ करने के लिए एक संकलक विकल्प दोषों की पहचान करने के लिए उपयोगी हो सकता है, लेकिन इसके अंतिम मूल्य को पकड़े हुए भंडारण को छोड़ना कभी-कभी मुखौटा दोष हो सकता है।
सुपरकैट

22

एक स्थिरता से, सिंटैक्टिक, दृष्टिकोण के बजाय, विचार की कम से कम तीन ट्रेनें हैं:

  1. फ़ंक्शन की शुरुआत में सभी चर घोषित करें ताकि वे एक ही स्थान पर रहें और आप एक नज़र में व्यापक सूची देख पाएंगे।

  2. सभी वैरिएबल को घोषित करें जितना संभव हो पहले इस्तेमाल की जाने वाली जगह के करीब, इसलिए आपको पता चल जाएगा कि प्रत्येक की आवश्यकता क्यों है।

  3. अंतरतम गुंजाइश ब्लॉक की शुरुआत में सभी चर घोषित करें, इसलिए वे जितनी जल्दी हो सके दायरे से बाहर हो जाएंगे और संकलक को स्मृति का अनुकूलन करने की अनुमति देंगे और आपको बताएंगे कि क्या आप गलती से उनका उपयोग करते हैं जहां आपने इरादा नहीं किया था।

मैं आम तौर पर पहला विकल्प पसंद करता हूं, क्योंकि मुझे लगता है कि अन्य लोग अक्सर घोषणाओं के लिए मुझे कोड के माध्यम से शिकार करने के लिए मजबूर करते हैं। सामने वाले सभी चरों को परिभाषित करना उन्हें डीबगर से आरंभ करना और देखना आसान बनाता है।

मैं कभी-कभी छोटे दायरे के ब्लॉक के भीतर चर घोषित करूंगा, लेकिन केवल एक अच्छे कारण के लिए, जिसमें से मेरे पास बहुत कम हैं। एक उदाहरण एक के बाद हो सकता है fork(), केवल बच्चे की प्रक्रिया द्वारा आवश्यक चर घोषित करने के लिए। मेरे लिए, यह दृश्य संकेतक उनके उद्देश्य का एक सहायक अनुस्मारक है।


27
मैं विकल्प 2 या 3 का उपयोग करता हूं, इसलिए चर खोजना आसान है - क्योंकि फ़ंक्शन इतने बड़े नहीं होने चाहिए कि आप चर घोषणाएं नहीं देख सकें।
जोनाथन लेफ्लर

8
विकल्प 3 एक गैर-मुद्दा है, जब तक कि आप 70 के दशक के एक कंपाइलर का उपयोग नहीं करते हैं।
edgar.holleis

15
यदि आपने एक सभ्य आईडीई का उपयोग किया है, तो आपको कोड शिकार पर जाने की आवश्यकता नहीं होगी, क्योंकि आपके लिए घोषणा को खोजने के लिए आईडीई-कमांड होना चाहिए। (ग्रहण में F3)
edgar.holleis

4
मुझे समझ में नहीं आता है कि आप विकल्प 1 में आरंभीकरण कैसे सुनिश्चित कर सकते हैं, हो सकता है कि आप केवल बाद में ब्लॉक में प्रारंभिक मूल्य प्राप्त कर सकते हैं, किसी अन्य फ़ंक्शन को कॉल करके या कैक्ल्यूलेशन कर सकते हैं।
प्लूमनेटर

4
@ प्लमनेटर: विकल्प 1 आरंभीकरण सुनिश्चित नहीं करता है; मैंने घोषणा पर उन्हें आरंभ करने के लिए चुना, या तो उनके "सही" मानों के लिए या कुछ ऐसा जो बाद के कोड की गारंटी देगा अगर वे उचित रूप से सेट नहीं होते हैं। मैं कहता हूं "चुना हुआ" क्योंकि मेरी प्राथमिकता # 2 में बदल गई है क्योंकि मैंने इसे लिखा है, शायद इसलिए कि मैं अब सी से अधिक जावा का उपयोग कर रहा हूं, और क्योंकि मेरे पास बेहतर देव उपकरण हैं।
एडम लेस

6

जब तक दूसरों द्वारा नोट किया जाता है, जीसीसी इस संबंध में अनुमति है (और संभवतः अन्य संकलक, उन तर्कों के आधार पर, जिनके साथ उन्हें कहा जाता है) तब भी जब 'C89' मोड में, जब तक आप 'पांडित्य' जाँच का उपयोग नहीं करते। ईमानदार होने के लिए, पांडित्य पर नहीं होने के कई अच्छे कारण नहीं हैं; गुणवत्ता आधुनिक कोड हमेशा चेतावनी के बिना संकलित होना चाहिए (या बहुत कम जहाँ आप जानते हैं कि आप कुछ विशिष्ट कर रहे हैं जो संकलक के लिए एक संभावित गलती के रूप में संदेहास्पद है), इसलिए यदि आप अपने कोड को पांडित्यपूर्ण सेटअप के साथ संकलित नहीं कर सकते हैं तो शायद इसे कुछ ध्यान देने की आवश्यकता है।

C89 को प्रत्येक स्कोप के भीतर किसी भी अन्य स्टेटमेंट से पहले वैरिएबल घोषित करने की आवश्यकता होती है, बाद में मानकों का उपयोग करने के लिए घोषणा को करीब से अनुमति देता है (जो अधिक सहज और अधिक कुशल दोनों हो सकता है), विशेष रूप से एक साथ घोषणा और लूप नियंत्रण चर के लिए 'लूप्स' के लिए आरंभीकरण।


0

जैसा कि उल्लेख किया गया है, इस पर विचार के दो स्कूल हैं।

1) वर्ष 1987 है क्योंकि कार्यों के शीर्ष पर सब कुछ घोषित करें।

2) पहले उपयोग के लिए निकटतम और संभव सबसे छोटे दायरे में घोषित करें।

मेरा जवाब है यह दोनों है! मुझे समझाने दो:

लंबे कार्यों के लिए, 1) रिफैक्टरिंग को बहुत कठिन बनाता है। यदि आप एक ऐसे कोडबेस में काम करते हैं जहाँ डेवलपर्स सबरूटीन्स के विचार के खिलाफ हैं, तो आपके पास फंक्शन की शुरुआत में 50 परिवर्तनीय घोषणाएँ होंगी और उनमें से कुछ सिर्फ फॉर-लूप के लिए "i" हो सकती हैं समारोह के नीचे।

इसलिए मैंने इससे घोषित-ए-टॉप-पीटीएसडी विकसित किया और धार्मिक रूप से विकल्प 2) करने की कोशिश की।

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

इसके अलावा, जब आप शीर्ष पर घोषित करना चाहते हैं, तो "एनएलआर को घोषित और सेट करें" का विरोधी पैटर्न, लेकिन आपने गणना के लिए आवश्यक कुछ गणनाओं को हल नहीं किया है क्योंकि आपको जिन चीजों को शुरू करने की आवश्यकता है उन्हें तर्क के रूप में प्राप्त किया जाएगा।

तो अब मेरी सोच यह है कि आपको पहले उपयोग के लिए फ़ंक्शन के शीर्ष पर और जितना संभव हो उतना निकट घोषित करना चाहिए। इसलिए दोनों! और ऐसा करने का तरीका अच्छी तरह से विभाजित सबरूटीन के साथ है।

लेकिन अगर आप एक लंबे कार्य पर काम कर रहे हैं, तो पहले उपयोग के लिए चीजों को निकटतम रखें क्योंकि इस तरह से तरीकों को निकालना आसान होगा।

मेरी रेसिपी यही है। सभी स्थानीय चर के लिए, चर लें और इसे नीचे की ओर घोषणा घोषित करें, संकलन करें, फिर संकलन त्रुटि से ठीक पहले घोषणा को स्थानांतरित करें। वह पहला उपयोग है। सभी स्थानीय चर के लिए ऐसा करें।

int foo = 0;
<code that uses foo>

int bar = 1;
<code that uses bar>

<code that uses foo>

अब, एक गुंजाइश ब्लॉक को परिभाषित करें जो घोषणा से पहले शुरू होता है और कार्यक्रम के संकलन तक अंत को स्थानांतरित करता है

{
    int foo = 0;
    <code that uses foo>
}

int bar = 1;
<code that uses bar>

>>> First compilation error here
<code that uses foo>

यह संकलित नहीं करता है क्योंकि कुछ और कोड है जो फू का उपयोग करता है। हम देख सकते हैं कि संकलक कोड का उपयोग करने में सक्षम था जो बार का उपयोग करता है क्योंकि यह फू का उपयोग नहीं करता है। इस बिंदु पर, दो विकल्प हैं। मैकेनिकल को बस "}" को नीचे की ओर ले जाना है जब तक कि वह संकलित न हो जाए, और दूसरी पसंद कोड का निरीक्षण करना और यह निर्धारित करना है कि क्या ऑर्डर को इसमें बदला जा सकता है:

{
    int foo = 0;
    <code that uses foo>
}

<code that uses foo>

int bar = 1;
<code that uses bar>

यदि आदेश को स्विच किया जा सकता है, तो शायद यही आप चाहते हैं क्योंकि यह अस्थायी मूल्यों के जीवनकाल को छोटा करता है।

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

int i;

for(i = 0; i < 8; ++i){
    ...
}

<some stuff>

for(i = 3; i < 32; ++i){
    ...
}

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

लेकिन पहला कदम पहला उपयोग मिल रहा है। आप इसे नेत्रहीन रूप से कर सकते हैं लेकिन कभी-कभी, घोषणा को हटाना आसान है, संकलन करने का प्रयास करें और इसे पहले उपयोग के ऊपर वापस रखें। यदि वह पहला उपयोग किसी इफ स्टेटमेंट के अंदर है, तो उसे वहां रखें और जांच करें कि क्या वह कंपाइल करता है। कंपाइलर फिर अन्य उपयोगों की पहचान करेगा। एक स्कोप ब्लॉक बनाने की कोशिश करें जिसमें दोनों उपयोग शामिल हों।

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


0

आपको फ़ंक्शन में शीर्ष या "स्थानीय" सभी चर घोषित करना चाहिए। उत्तर है:

निर्भर करता है पर है कि आप किस तरह का सिस्टम इस्तेमाल कर रहे हैं:

1 / एंबेडेड सिस्टम (विशेष रूप से हवाई जहाज या कार की तरह जीवन से संबंधित): यह आपको डायनामिक मेमोरी (जैसे: कॉलोक, मॉलोक, नया ...) का उपयोग करने की अनुमति देता है। कल्पना कीजिए कि आप 1000 इंजीनियरों के साथ एक बहुत बड़ी परियोजना में काम कर रहे हैं। क्या होगा यदि वे नई गतिशील मेमोरी आवंटित करते हैं और इसे हटाने के लिए भूल गए (जब यह अब उपयोग नहीं करता है)? यदि एम्बेडेड सिस्टम लंबे समय तक चलता है, तो इससे स्टैक ओवरफ्लो हो जाएगा और सॉफ्टवेयर भ्रष्ट हो जाएगा। गुणवत्ता सुनिश्चित करने के लिए आसान नहीं है (सबसे अच्छा तरीका है गतिशील मेमोरी को प्रतिबंधित करना)।

यदि कोई हवाई जहाज 30 दिनों में चलता है और टर्नऑफ नहीं करता है, तो क्या होगा यदि सॉफ़्टवेयर दूषित है (जब हवाई जहाज अभी भी हवा में है)?

2 / अन्य सिस्टम जैसे वेब, पीसी (बड़ी मेमोरी स्पेस है):

आपको मेमोरी का उपयोग करने के लिए चर "स्थानीय रूप से" घोषित करना चाहिए। अगर ये सिस्टम लंबे समय तक चलता है और स्टैक ओवरफ्लो होता है (क्योंकि कोई व्यक्ति डायनेमिक मेमोरी को हटाना भूल गया)। पीसी को रीसेट करने के लिए बस आसान काम करें: इसका जीवन पर कोई प्रभाव नहीं है


मुझे यकीन नहीं है कि यह सही है। मुझे लगता है कि आप कह रहे हैं कि मेमोरी लीक के लिए ऑडिट करना आसान है अगर आप एक ही स्थान पर अपने सभी स्थानीय चर घोषित करते हैं? यह सच हो सकता है, लेकिन मुझे यकीन नहीं है कि मैं इसे खरीदूंगा। बिंदु (2) के लिए, आप कहते हैं कि स्थानीय रूप से परिवर्तनीय घोषित करने से "मेमोरी उपयोग का अनुकूलन होगा"? यह सैद्धांतिक रूप से संभव है। एक संकलक मेमोरी के उपयोग को कम करने के लिए एक फ़ंक्शन के दौरान स्टैक फ्रेम का आकार बदलने का विकल्प चुन सकता है, लेकिन मुझे ऐसा करने वाले किसी के बारे में पता नहीं है। वास्तव में, संकलक सभी "स्थानीय" घोषणाओं को "पर्दे के पीछे से कार्य करना" शुरू कर देगा।
क्विनफ्रीडरमैन

1 / एंबेडेड सिस्टम कभी-कभी गतिशील मेमोरी की अनुमति नहीं देता है, इसलिए यदि आप फ़ंक्शन के शीर्ष में सभी चर घोषित करते हैं। जब स्रोत कोड बनाया जाता है, तो यह प्रोग्राम को चलाने के लिए ढेर की बाइट की संख्या की गणना कर सकता है। लेकिन गतिशील मेमोरी के साथ, कंपाइलर ऐसा नहीं कर सकता है।
डांग_हो

2 / यदि आप स्थानीय रूप से एक चर घोषित करते हैं, तो वह चर केवल "{}" खुले / बंद ब्रैकेट के अंदर मौजूद होता है। तो संकलक चर के स्थान को मुक्त कर सकता है यदि वह चर "दायरे से बाहर" हो। यह फ़ंक्शन के शीर्ष पर सब कुछ घोषित करने से बेहतर हो सकता है।
डांग_हो at

मुझे लगता है कि आप स्थिर बनाम गतिशील मेमोरी के बारे में उलझन में हैं। स्टैटिक पर स्टैटिक मेमोरी आवंटित की जाती है। सभी चर जो किसी फ़ंक्शन में घोषित किए जाते हैं, कोई फर्क नहीं पड़ता कि वे कहाँ घोषित किए जाते हैं, सांख्यिकीय रूप से आवंटित किए जाते हैं। डायनामिक मेमोरी को ढेर पर आवंटित किया जाता है जैसे कुछ malloc()। हालांकि मैंने कभी ऐसा उपकरण नहीं देखा है जो इसके लिए अक्षम है, यह एम्बेडेड सिस्टम पर गतिशील आवंटन से बचने के लिए सबसे अच्छा अभ्यास है ( यहां देखें )। लेकिन इससे कोई लेना-देना नहीं है कि आप एक समारोह में अपने चर कहां से घोषित करते हैं।
क्विनफ्रीडमैन

1
जबकि मैं मानता हूं कि यह काम करने का एक उचित तरीका होगा, व्यवहार में ऐसा नहीं है। यहां आपके उदाहरण के लिए बहुत कुछ के लिए वास्तविक विधानसभा है: godbolt.org/z/mLhE9a । जैसा कि आप देख सकते हैं, लाइन 11 पर, sub rsp, 1008इफ स्टेटमेंट के बाहर पूरे एरे के लिए जगह आवंटित कर रहा है । इस के लिए सच है clangऔर gccहर संस्करण और अनुकूलन के स्तर मैंने कोशिश की पर।
QuinnFreedman

-1

मैं स्पष्ट विवरण के लिए gcc संस्करण 4.7.0 के लिए मैनुअल से कुछ कथन उद्धृत करूंगा।

"संकलक कई आधार मानकों को स्वीकार कर सकता है, जैसे 'c90' या 'c ++ 98', और GNU बोलियाँ उन मानकों की, जैसे 'gnu90' या 'gnu ++ 98'। आधार मानक को निर्दिष्ट करके, संकलक। उस मानक और GNU एक्सटेंशन का उपयोग करने वाले सभी कार्यक्रमों को स्वीकार करेंगे जो इसके विपरीत नहीं हैं। उदाहरण के लिए, '-std = c90' GCC की कुछ विशेषताओं को बंद कर देता है जो आईएसओ C90 के साथ असंगत हैं, जैसे कि asm और टाइप कीवर्ड, लेकिन नहीं अन्य GNU एक्सटेंशन जिनका ISO C90 में कोई अर्थ नहीं है, जैसे कि? का मध्य पद छोड़ना ?: अभिव्यक्ति। "

मुझे लगता है कि आपके प्रश्न का मुख्य बिंदु यह है कि विकल्प "-dd = c89" का उपयोग करने पर भी C89 के अनुरूप क्यों नहीं होगा। मुझे आपके gcc के संस्करण का पता नहीं है, लेकिन मुझे लगता है कि बड़ा अंतर नहीं होगा। Gcc के डेवलपर ने हमें बताया है कि विकल्प "-std = c89" का अर्थ है कि C89 के विरोधाभासी एक्सटेंशन को बंद कर दिया गया है। तो, इसका कुछ एक्सटेंशनों से कोई लेना-देना नहीं है जिनका C89 में कोई अर्थ नहीं है। और चर घोषणा को प्रतिबंधित नहीं करने वाला विस्तार C89 के विरोधाभासी नहीं होने वाले एक्सटेंशन के अंतर्गत आता है।

ईमानदार होने के लिए, हर कोई यह सोचेगा कि इसे "-std = c89" विकल्प की पहली नजर में पूरी तरह से C89 के अनुरूप होना चाहिए। लेकिन यह नहीं है। समस्या है कि शुरुआत में सभी चर घोषित बेहतर या बुरा है के लिए के रूप में सिर्फ एक आदत का मामला है।


अनुरूपता का अर्थ विस्तार को स्वीकार नहीं करना है: जब तक कंपाइलर वैध कार्यक्रमों को संकलित करता है और दूसरों के लिए किसी भी आवश्यक निदान का उत्पादन करता है, यह अनुरूप होता है।
मोनिका

@ मर्क लेहमैन, हां, आप सही हैं जब शब्द "अनुरूप" का उपयोग संकलक को अलग करने के लिए किया जाता है। लेकिन जब शब्द "अनुरूप" का उपयोग कुछ उपयोगों का वर्णन करने के लिए किया जाता है, तो आप कह सकते हैं "एक उपयोग मानक के अनुरूप नहीं है।" और सभी शुरुआती लोगों की एक राय है कि जो मानक मानक के अनुरूप नहीं हैं, उनमें त्रुटि का कारण होना चाहिए।
12

@Marc Lehmann, वैसे, कोई निदान नहीं है जब gcc उस उपयोग को देखता है जो C89 मानक के अनुरूप नहीं है।
सेंघ

आपका उत्तर अभी भी गलत है, क्योंकि "जीसीसी के अनुरूप नहीं" का दावा करना "कुछ उपयोगकर्ता कार्यक्रम के अनुरूप नहीं है" के समान नहीं है। आपके अनुरूप उपयोग केवल गलत है। इसके अलावा, जब मैं एक शुरुआत करने वाला था तो मैं आपकी राय के अनुसार नहीं था, इसलिए यह भी गलत है। अंत में, गैर-अनुरूपता कोड का निदान करने के लिए एक अनुरूप संकलक की कोई आवश्यकता नहीं है, और वास्तव में, इसे लागू करना असंभव है।
मोनिका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.