2016-03-12 10 views
11

मैं निम्नलिखित कार्यक्रम है:सरणी पूर्णांक वी के रूप में घोषित [100] लेकिन और (v [100]) कोई चेतावनी देता है

#include <stdio.h> 

int main() { 

    int v[100]; 
    int *p; 

    for (p = &(v[0]); p != &(v[100]); ++p) 
     if ((*p = getchar()) == EOF) { 
      --p; 
      break; 
     } 

    while (p != v) 
     putchar(*--p); 

    return 0; 
} 

और इस टर्मिनल पर gcc --version के उत्पादन में है:

Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 
Apple LLVM version 7.0.2 (clang-700.1.81) 
Target: x86_64-apple-darwin15.3.0 
Thread model: posix 

क्यों एक सरणी के अंतिम के बाद तत्व का पता हो रही है मुझे कोई चेतावनी लेकिन उदाहरण के लिए हो रही है v[101] का पता मुझे निम्न चेतावनी देता है देता है

test.c:8:29: warning: array index 101 is past the end of the array (which 
     contains 100 elements) [-Warray-bounds] 
    for(p = &(v[0]); p != &(v[101]); ++p) 
          ^~~~ 
test.c:5:5: note: array 'v' declared here 
    int v[100]; 
    ^
1 warning generated. 
,210

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

+1

आपका प्रोग्राम * अपरिभाषित व्यवहार * का आह्वान करेगा यदि केवल ईओएफ से पहले शून्य अक्षर पढ़े जाते हैं। – MikeCAT

+2

आपको 'EOF' पर' p' कम नहीं करना चाहिए। – chqrlie

+0

@chqrlie आप यह कहते हैं क्योंकि निम्न में लूप में पहली बार 'पी' कम हो जाती है और फिर इसे अस्वीकार कर दिया जाता है? – nbro

उत्तर

14

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

N1256 6.5.2.1 सरणी

subscripting सबस्क्रिप्ट ऑपरेटर [] की परिभाषा है कि ई 1 [E2] के समान है है (* ((ई 1) + (E2)))।

N1256 6.5.3.2 पता और अविवेक ऑपरेटरों

संकार्य एक एकल * ऑपरेटर, न कि ऑपरेटर का परिणाम है और न ही & ऑपरेटर मूल्यांकन किया जाता है और परिणाम है के रूप में यदि दोनों थे, तो , छोड़े गए, सिवाय इसके कि ऑपरेटरों पर कमी अभी भी लागू करते हैं और परिणाम एक lvalue नहीं है। इसी प्रकार, यदि ऑपरेंड एक [] ऑपरेटर का नतीजा है, न तो & ऑपरेटर और न ही असाइन * जो कि [] द्वारा निहित है, का मूल्यांकन किया गया है और नतीजा यह है कि & ऑपरेटर हटा दिए गए थे और [] ऑपरेटर थे एक + ऑपरेटर में बदल गया।

N1256 6.5.6 Additive ऑपरेटरों

इसके अलावा, अगर एक सरणी वस्तु के अंतिम तत्व, अभिव्यक्ति (पी) +1 अंक एक के अंतिम तत्व के बाद करने के लिए अभिव्यक्ति पी अंक सरणी वस्तु, और अभिव्यक्ति क्यू अंक एक सरणी वस्तु के अंतिम तत्व के बाद एक, अभिव्यक्ति (क्यू) -1 अंक सरणी वस्तु के अंतिम तत्व को

+2

ईमानदारी से, उद्धरण मेरे प्रश्न का उत्तर नहीं देते हैं। आप यह भी कह रहे हैं कि एक सरणी के अंतिम तत्व के पीछे एक पॉइंटर को स्थानांतरित करने की अनुमति है (और उद्धरण वास्तव में आप जो कह रहे हैं उससे संबंधित नहीं हैं), लेकिन मैं वास्तव में _also_ के पिछले तत्व का पता प्राप्त कर रहा हूं अंतिम तत्व (पहले इसे एक्सेस करके) ... – nbro

+0

@nbro एक उद्धरण भी है कि '& * X' को 'एक्स' जैसा ही परिभाषित किया गया है, इसलिए जब आप इसे इस उत्तर में पहले उद्धरण के साथ जोड़ते हैं, तो आप देखते हैं कि '& v [100] 'को' (v + 100) 'के रूप में परिभाषित किया गया है जो अंतिम उद्धरण –

+0

के अनुसार कानूनी है, इसे एक और तरीका रखने के लिए, * * (v + 100)' के बारे में बात करना केवल अपरिभाषित है यदि आप कोशिश करते हैं –

0

यह कंपनियों के बारे में है, तो ढीले लिखित कोड के साथ स्थिरता।

जैसा कि माइककैट ने एक सरणी int ar[N] के लिए उद्धृत किया है, अभिव्यक्ति ar+N मान्य है और परिणामस्वरूप एक पॉइंटर होता है जो पिछले-अंत-अंत स्थिति को इंगित करता है। हालांकि इस सूचक को संदर्भित नहीं किया जा सकता है, इसकी तुलना किसी भी अन्य सूचक से सरणी में की जा सकती है, जो आपको for (p = ar; p != ar+N; ++p) लूप लिखने की अनुमति देती है।

इसके अलावा, प्रोग्रामर यदि आप एक सरणी के i वें तत्व के लिए सूचक चाहते हैं, पठनीय कोड लिखने के लिए, और यकीनन, &ar[i] बता देते हैं अपने इरादे ar + i लिखने की तुलना में अधिक स्पष्ट रूप से लेखन की तरह।

इन दो कम्बाइन, और आप प्रोग्रामर जो &ar[N] लिखने पास्ट अंत सूचक प्राप्त करने के लिए मिल जाएगा, और जब यह तकनीकी रूप से गलत सरणी सूचकांक तक पहुँच रहा है, कोई संकलक कभी ar + N से कुछ और के रूप में इस को लागू करेगा - में तथ्य यह है कि कंपाइलर को इसे अलग करने के तरीके से बाहर जाना होगा। वास्तव में काफी दूर।

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

+0

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

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