2012-09-23 8 views
6

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

while (totalBytesRecvd < echoStrLen) 
{ 
    char buffer[BUFSIZE]; 
    numBytes = recv(sock, buffer, BUFSIZE - 1, 0); 
    ... 
    totalBytesRecvd += numBytes; 
    buffer[numBytes] = '\0'; 
    fputs(buffer, stdout); 
} 

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

क्या लूप के अंदर बार-बार एक बफर को परिभाषित करने का एक विशिष्ट कारण है? या यह मेरी सही समझ है?

उत्तर

8

recv, read और अन्य समान कार्यों के रूप में, बफर की पिछली सामग्री की परवाह नहीं करता है, यह केवल परिणाम लिखने के लिए इसका उपयोग करता है।

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

इसके अलावा

, सबसे सी कार्यान्वयन पर:

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

जाहिर है, बजाय, यदि आप अपने चर प्रारंभ यह अलग होगा - प्रारंभ प्रदर्शन करने के लिए कोड प्रत्येक यात्रा पर चलाना होगा; लेकिन, जैसा ऊपर बताया गया है, कुछ भी शुरू करने की कोई आवश्यकता नहीं है, recv बस बफर की वर्तमान स्थिति की परवाह नहीं करता है।

+0

+1, मेरे उत्तर से काफी बेहतर रखा गया है। – Martin

+0

सभी बहुत उपयोगी (और समान) उत्तर अब तक है। क्या कोई मुझे अपने स्रोत पर इंगित कर सकता है? या क्या मैं इसे अपने कंपाइलर दस्तावेज़ में ढूंढ सकता हूं? संकलक अनुकूलन को सी प्रोग्रामिंग पुस्तक में पढ़ा गया था जिसे मैंने पढ़ा था। – Nocturno

+2

मेरा स्रोत संकलक द्वारा उत्पन्न असेंबलर को देखने में बहुत अधिक समय बिताया गया है :)। सामान्य रूप से, इस तरह के अनुकूलन के बारे में चिंता मत करो। सही नौकरी के लिए सही एल्गोरिदम का उपयोग करें, और केवल इन प्रकार के tweaks पर विचार करें यदि आप कोड * जरूरत * अनुकूलन का एक टुकड़ा प्रदर्शित कर सकते हैं। – Martin

2

लूप के अंदर एक चर घोषित करने के लिए बस इसके लिए स्टैक स्पेस आरक्षित करता है; यह सामग्री को साफ़ नहीं करेगा या अन्यथा चर को स्पर्श नहीं करेगा। इस प्रकार, घोषणा की यह शैली लूप के बाहर घोषित करने से कहीं अधिक महंगा नहीं है।

5

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

2

एक पाश में एक चर को परिभाषित करना ही बुरा अगर यह निर्माण करने के लिए महंगा है, और कहा कि शायद ही कभी सी में मामला

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

सी ++ में, आप एक महंगे कन्स्ट्रक्टर के साथ एक चर घोषित करने के बारे में सोच सकते हैं यदि आप लूप के बाहर एक बार इसे बनाने के साथ दूर हो सकते हैं, लेकिन यह कोई मुद्दा नहीं होगा।

1

मैं हमेशा इस धारणा के तहत रहा हूं कि मुझे एक लूप के अंदर चर परिभाषित नहीं करना चाहिए क्योंकि यह अनावश्यक या अपर्याप्त है।

तुम हमेशा एक गलत धारणा के तहत किया गया रहे हैं, और एक है कि न केवल निराधार है, लेकिन एक बहुत बुरा व्यवहार गड्ढे - समय से पहले अनुकूलन - एक बहुत अच्छा एक के खिलाफ, के रूप में उनके उपयोग के करीब के रूप में चर घोषित मुमकिन।

1

मुझे यह भी लगता था कि लूपों से बाहर चलने वाली घोषणाओं का परिणाम तेजी से कोड होगा, खासकर बड़े संरचनाओं जैसे कि सरणी के लिए। मुझे लगता है कि यह अक्सर malloc'd (ढेर) डेटा के साथ सच है, क्योंकि आप malloc बुलाकर और लूप के भीतर मुक्त करके ओवरहेड पर बहुत बर्बाद कर सकते हैं। स्टैक डेटा के लिए (जैसे आपकी) मैं इसे किसी समस्या के बड़े के रूप में नहीं सोचता।

हालांकि, मुझे हाल ही में विपरीत स्थिति का सामना करना पड़ा, जहां मैंने एक आंतरिक लूप से घोषणा की और वास्तव में धीमी कोड के साथ समाप्त हो गया। मैं इस के लिए कुछ संभावित कारण हो के साथ आया था:

  1. जब घोषणा व्यापक गुंजाइश के लिए ले जाया गया था संकलक के रूप में प्रभावी रूप से कोड का अनुकूलन करने में सक्षम नहीं था।
  2. लूप पुनरावृत्तियों के बीच स्मृति में बड़ी मात्रा में डेटा रखा जा रहा था, जिसके परिणामस्वरूप अक्षम कैश उपयोग होता था।

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

+0

'मैं यह भी सोचता था कि लूपों से बाहर निकलने वाली घोषणाओं के परिणामस्वरूप तेज कोड होगा, खासकर बड़े संरचनाओं जैसे कि सरणी के लिए।' - * तुमने ऐसा क्यों सोचा? 'मुझे लगता है कि यह अक्सर malloc'd (ढेर) डेटा के साथ सच है' - आवंटन घोषणा नहीं है! यदि आपके पास 'int foo = very_long_calculation (rand()) जैसा कोई बयान था; तो निश्चित रूप से * लूप के अंदर * गणना * को स्थानांतरित करना महंगा होगा। किसी भी अलग malloc करने के लिए एक कॉल कैसे है? –

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