2012-05-01 15 views
10

में मौजूद है, सालों से, मुझे लूप निकास के बाद for लूप इटरेटर के मान का उपयोग न करने की आदत में शामिल हो गया है। मैं शपथ ले सकता था कि मैंने ऐसा किया, क्योंकि यह एक कंपाइलर चेतावनी उत्पन्न करता था, लेकिन हाल ही में कोड समीक्षा में मुझे चुनौती देने के बाद, मैं गलत साबित हुआ।लूप के बाद 'फॉर' लूप इटरेटर का उपयोग सी

उदाहरण के लिए, मैं हमेशा इस (: हमारे कोड के मानकों "तोड़" कीवर्ड के उपयोग को प्रतिबंधित नोट): किया

int i, result; 
bool done = false; 
for (i=0; i<10 && !done; i++) { 
    if (some_condition) { 
     result = i; 
     done = true; 
    } 
} 
// Value of i may be undefined here 

अब, जाहिर है result चर हटाया जा सकता है, अगर मैं पर भरोसा कर सकते मैं का मूल्य मैंने सोचा कि संकलक अनुकूलन के कारण, आप लूप इटरेटर के मूल्य पर भरोसा नहीं कर सके। क्या मैं बस एक प्रेत शिक्षण याद कर रहा हूँ? या यह मानक है (विशेष रूप से जीएनयू सी के संबंध में)?

+13

* "(नोट: हमारे कोड मानकों" ब्रेक "कीवर्ड के उपयोग को प्रतिबंधित करते हैं): * * - क्षमा करें, लेकिन डब्ल्यूटीएफ? –

+4

'ब्रेक' के साथ कुछ भी गलत नहीं है –

+0

यदि मुझे सही मिनट याद है तो आप इटरेटर सीमा में दूसरा चर प्रस्तुत करते हैं तो सी 99 के अधिकांश ऑप्टिमाइज़ेशन आपको विंडो से बाहर जाने दे सकते हैं। इसके बाद मैं एक ++ के साथ थोड़ी देर लूप से बेहतर नहीं हूं; अतं मै। –

उत्तर

10

C89, C99, या C11 में for बयान के बाद यात्रा चर का उपयोग करने की गलत कुछ भी नहीं है।

int i; 

for (i = 0; i < 10; i++) { 
    /* Some code */ 
} 

printf("%d\n", i); // No magic, the value is 10 

C99 से, आपके पास एक घोषणा for बयान के पहले खंड के रूप में उपयोग कर सकते हैं, और निश्चित रूप से उस मामले में घोषित चर for बयान के बाद नहीं किया जा सकता।

+2

क्या आप अपने 'printf' में' 10' के बजाय 'i' का उपयोग करना चाहते हैं? – Nick

+1

@ निक हे, वास्तव में धन्यवाद :) – ouah

+1

उत्कृष्ट। धन्यवाद। मुझे यकीन नहीं है कि यह आदत मेरी कोड शैली में कैसे प्रवेश करती है, और मैं सही हूं।सी में लूप पूर्ण होने के बाद लूप इटरेटर के लिए (ठीक से स्कॉप्ड) का उपयोग करने में कुछ भी गलत नहीं है। –

0

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

उदाहरण के लिए, निम्नलिखित कोड पर विचार करें:

int more_work_to_do(void) 
{ 
    return 1; 
} 

int some_condition(void) 
{ 
    return 1; 
} 

int foo() 
{ 
    int i = 100; 

    while (more_work_to_do()) { 
     int done = 0; 

     for (int i = 0; i < 10 && !done; i++) { 
      if (some_condition()) { 
       done = 1; 
      } 
     } 

     if (done) return i; // which `i`? 
    } 

    return 1; 
} 

ifor पाश में घोषित करने के लिए तय करने के कुछ पुराने नियमों के तहत, मूल्य बयान टिप्पणी के साथ चिह्नित पर लौट आए "जो i" होगा for लूप द्वारा निर्धारित (वीसी ++ 6 इन नियमों का उपयोग करता है)। उस चर के स्कॉइंग के लिए नए, मानक नियमों के तहत, फ़ंक्शन की शुरुआत में घोषित मूल्य i होगा।

+0

दरअसल, इस अभ्यास से बचा जाने का कारण पूरी तरह से सी ++ के कारण है - यह ऐतिहासिक असंगतता, और एक सामान्य सी ++ दर्शन है कि इटरेटर लूप के लिए स्थानीय होना चाहिए। आईएमओ में सी से बचने का कोई अच्छा कारण नहीं है, जो एक पूरी तरह से अलग भाषा है –

+0

भले ही आप केवल सी 99 मानक व्यवहार पर विचार करें, फिर भी अंतर अंतर में 'i' को फिर से चलाने से बचने के कारण हो सकते हैं, उदाहरण के लिए परिचय रोकने में मदद के लिए रखरखाव के दौरान त्रुटियां। एरिक लिपर्ट के आलेख को सी # के लिए एक तर्क बताते हुए स्थानीय चर के कई पुनर्विक्रयों को स्पष्ट रूप से त्रुटियों को समझाते हुए देखें: http://blogs.msdn.com/b/ericlippert/archive/2009/11/02/simple-names-are-not-so- simple.aspx मुझे पता है कि यह फिर से एक अलग भाषा है, लेकिन भाषा डिजाइनरों ने बग के इतिहास पर आकर्षित किया जो सुझाव दिया कि यह एक समस्या क्षेत्र था। –

+0

जब मैंने कहा "इससे बचें", तो मुझे लूप के बाद 'i' का उपयोग करने से बचने का मतलब था। मुझे सी में ऐसा करने से बचने का कोई कारण नहीं दिखता है। व्यक्तिगत रूप से मैं हमेशा लूप में 'i' को स्कॉइंग करने से बचता हूं, क्योंकि लूप समाप्त होने के बाद मैं इसके मूल्य का उपयोग करना पसंद करता हूं, और कारण के कारण (किसी अन्य चर को छायांकन का जोखिम), भले ही जीसीसी बाद के बारे में चेतावनी पर अच्छा है। –

2

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

/*find the index of the first element which is odd*/ 
for (ii = 0; ii < nelem && arry[ii] % 2 == 0; ii++); 

के रूप में उल्लेख किया है, भ्रम की स्थिति की बात संरचनाओं से आ सकता है जहां इटेटर स्वयं को कथन के भीतर परिभाषित किया जाता है।

सामान्य रूप से कथन के लिए बहुत शक्तिशाली हैं, और यह दुर्भाग्यपूर्ण है कि आमतौर पर उनका पूर्ण क्षमता तक कभी उपयोग नहीं किया जाता है।

उदाहरण के लिए, एक ही पाश की एक अलग संस्करण के रूप में निम्नानुसार (हालांकि यह इटरेटर का उपयोग कर की सुरक्षा को प्रदर्शित नहीं होगा) लिखा जा सकता है:

#include <stdio.h> 
int main(void) 
{ 
    int cur, ii = 0, nelem, arry [] = { 1, 2, 4, 6, 8, 8, 3, 42, 45, 67 }; 
    int sum = 0; 

    nelem = sizeof(arry)/sizeof(int); 
    /* Look mom! no curly braces! */ 

    for (
      ii = 0; 
      ii < nelem && ((cur = arry[ii]) %2 == 0 || 
           ((printf("Found odd number: %d\n", cur)||1))); 
      ii++, sum += cur 
     ); 
    printf("Sum of all numbers is %d\n", sum); 
    return 0; 
} 

इस विशेष मामले में, यह एक तरह लगता है इस विशिष्ट समस्या के लिए बहुत सारे काम, लेकिन यह कुछ चीजों के लिए बहुत आसान हो सकता है।

+1

बहुत चिकनी। मुझे यह पसंद है। दुर्भाग्य से यह मेरे काम पर कोड समीक्षा पास नहीं करेगा :( –

4

विभिन्न भाषाओं में अलग-अलग नियम हैं। पास्कल में, संकलक को अंतिम वृद्धि के बाद लूप इंडेक्स को संग्रहीत करने के लिए ऑप्टिमाइज़ करने की अनुमति है, इसलिए पहला लूप-टर्मिनिंग मान हो सकता है या अंतिम वैध मान हो सकता है।

+2

मुझे लगता है कि आपको यह मिल गया है। पास्कल पहली भाषा थी जिसे मैंने वास्तव में सिखाया था, दस लाख साल पहले एपी कंप्यूटर पोर्ग्रामिंग में 1 99 5 में। मुझे लगता है कि यह आदत है मुझे ड्रिल किया गया था, और इसे सी में ले जाया गया। दिलचस्प ... –

0

जबकि मैं संभवतः यह नहीं जान सकता कि आपकी आदत कैसे हुई, मैं आपको बता सकता हूं कि मेरी आदत कैसा है।

for (i=0u; (i<someLimit) && (found != TRUE); i++) 
{ 
    if (someCondition) found = TRUE; 
} 
foundIndex = i-1; 

असल में, जब ब्रेक कीवर्ड कुछ कोडिंग नियमों द्वारा अनुमत नहीं है इस तरह कोड लिखा है, उदाहरण के लिए: यह इस तरह कोड देखकर था मिसा पर आधारित यदि आप लूप से बाहर नहीं निकलते हैं, तो लूप आमतौर पर आपको "i" के साथ छोड़ देगा जो आपकी देखभाल के लिए एक से बंद है।

कभी कभी, आप भी इस पा सकते हैं:

for (i=0u; (i<someLimit) && (found != TRUE); i++) 
{ 
    if (someCondition) found = TRUE; 
} 
foundIndex = i; 

यह सिर्फ शब्दार्थ गलत है और जब "ना करे कीवर्ड नियम तोड़ने" किसी मौजूदा कोड के आधार में शुरू की है जो पर्याप्त रूप से इकाई में शामिल नहीं है पाया जा सकता है परीक्षण। आश्चर्य की बात हो सकती है, लेकिन यह सब वहाँ है ...

+0

मिस्रा-सी: 2004 और मिसा-सी: 2012 के अंतिम दो संस्करणों में ब्रेक के खिलाफ ऐसे कोई नियम नहीं हैं, वास्तव में उनके उपयोग के कुछ सावधानी पूर्वक मार्गदर्शन हैं लूप्स, लेकिन उन्हें प्रतिबंधित नहीं करता है। – Veriloud

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