2013-11-14 8 views
6

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

// call unsigned chars bytes 
typedef unsigned char byte; 
byte trear = 0; // SCI transmit display buffer IN index 
byte tfront = 0; // SCI transmit display buffer OUT index 
byte tsize = 16; // size of transmit buffer 
byte tbuf[16]= {0};// SCI transmit display buffer 

ध्यान दें कि trear रियर तत्व की वास्तविक सूचकांक है, लेकिन tfront एक सामने तत्व की वास्तविक सूचकांक (विषय निश्चित रूप से 16 सापेक्ष करने के लिए) से कम है। तो, उदाहरण के लिए, अगर मेरे बफर निहित "हैलो", यह इस प्रकार दिखाई देंगे (जहां खाली स्लॉट हैं कचरा मान):

_________________________________ 
| | |h|e|l|l|o| | | | | | | | | | 
^  ^
front  rear 

जब यह कतार से एक बाइट दूर करने के लिए समय आ गया है, मैं यह कर:

// increment front index 
tfront++; 
// wrap front index if it exceeded bounds 
tfront %= tsize;       // (A) 
// get character to transmit 
byte outputChar = tbuf[tfront]; 

यह सब ठीक काम करता है - कम से कम, मेरे कार्यक्रम ने इस खंड से संबंधित कोई भी बग प्रदर्शित नहीं किया है। हालांकि, जब मैं इस कार्यक्रम को संकलित, मेरे संकलक मुझे लाइन के बारे में चेतावनी दी है टुकड़ा में (A) ऊपर चिह्नित, शिकायत:

चेतावनी: C2705: डेटा

main.c लाइन 402

के संभावित नुकसान

लाइन 402 लाइन (ए) है। मुझे ध्यान रखना चाहिए कि मैं जीसीसी या इसी तरह का उपयोग नहीं कर रहा हूं; मैं फ्रीस्केल के कोडवायरियर आईडीई में संकलित हूं, जिसने कभी-कभी मुझे कुछ और रहस्यमय चेतावनियां दी हैं।

// increment front index mod tsize 
tfront = (tfront + 1 >= tsize) ? 0 : tfront + 1;  // (B) 
// get character to transmit 
byte outputChar = tbuf[tfront]; 

लेकिन, मेरा संकलक अब भी वही चेतावनी, लाइन (B) के बारे में इस समय का उत्सर्जन करता है: चेतावनी से छुटकारा पाने के प्रयास में, मैं के रूप में ऊपर टुकड़ा दुबारा लिखा। शायद संकलक मुझे बता रहा है कि कथन (tfront + 1 >= tsize), tfront निष्पादन से पहले 255 हो सकता है, और अतिप्रवाह। बेशक, मुझे पता है कि यह नहीं होगा, लेकिन मेरा कंपाइलर नहीं करता है।

यदि यह मामला है, तो, क्यों (A) एक समस्या थी? असल में, मैं जानना चाहता हूं कि कंपाइलर किस बारे में नाखुश है।


मेरे सवाल का पूरा लिखने के बाद से, मैं इसे एक चर प्रकार से tsize बदलते एक पूर्वप्रक्रमक परिभाषा के द्वारा हल किया गया है (अर्थात, #define TSIZE 16)। मेरा सवाल अभी भी खड़ा है, यद्यपि।


कुछ संबंधित प्रश्न:
unsigned overflow with modulus operator in C
modulus operator with unsigned chars

+1

ध्यान दें कि tsize' 2 के एक शक्ति होने की गारंटी दी जा सकती है, तो ', यह थोड़ा मुखौटा का उपयोग करने के और अधिक कुशल है, और वह भी बड़े करीने से बचा जाता है एक कलाकार के बिना यह चेतावनी। तो 16 तत्वों के बफर के लिए, 'tfront = = 0x0f'' tfront% = 16' की बजाय। किसी भी 'tsize' के लिए सामान्य मामले में 2 की शक्ति है, आवश्यक मॉड-मास्क 'tsize - 1' है। – Clifford

+0

@Clifford यदि चेतावनी 'lval = expr; 'तक विस्तारित असाइनमेंट के कारण होती है, जहां' lval' टाइप' बाइट' और 'expr' टाइप' int' है, तो थोड़ा मास्क का उपयोग चेतावनी से नहीं बचाता है: ' tfront & = मुखौटा; 'tfront = tfront & mask;' और 'tfront & mask' में 'tfront% size' करता है (C99 6.3.1.1 बंद और 6.3.1.8:1" के कारण' int 'टाइप किया गया है पूर्णांक प्रचार दोनों ऑपरेटरों पर किया जाता है ")। –

+0

@Clifford इसके अतिरिक्त, किसी को bitwise ऑपरेटर को सही करने की आवश्यकता है। क्या आपका मतलब '&' था? –

उत्तर

5

संकलक चेतावनी संभावना इस तथ्य से आता tfront %= tsize;, जो क्योंकि सी में पदोन्नति नियमों अभिव्यक्ति tfront % tsize है की tfront = tfront % tsize; के बराबर है, में है कि (*) int टाइप करें।

यदि आप tfront = (byte)(tfront % tsize); लिखते हैं तो यह संकलक को चुप कर सकता है।

में चिंता करने की कोई विशेष कारण नहीं है, और अपने संकलक वास्तव में अजीब चेतावनी का उत्सर्जन करता है: हालांकि अभिव्यक्ति tfront % tsize तकनीकी रूप से टाइप int, अपने मूल्यों को सभी क्योंकि जिस तरह से यह गणना की जाती है की एक byte में फिट है। यहां तक ​​कि यदि मान byte में फिट नहीं होते हैं, तो लपेटने वाले व्यवहार को सी मानक द्वारा हस्ताक्षरित पूर्णांक प्रकारों के लिए गारंटी दी जाती है (ताकि आप उद्देश्य पर इस लपेटने वाले व्यवहार का उपयोग करने में उचित ठहर सकें)।

(*) जब तक आपके संकलन मंच int पर सभी मूल्यों है कि एक unsigned char ले जा सकते हैं, जिस स्थिति में यह प्रकार unsigned int का होगा नहीं हो सकते और आप शायद यह चेतावनी दिखाई नहीं होगा।

+0

जैसा आपने सुझाव दिया है, यह समस्या है। बहुत अंतर्दृष्टि, धन्यवाद। – ravron

+2

चेतावनी एकवचन रूप से अनुपयोगी है; झूठी सकारात्मक झूठी नकारात्मकताओं से भी बदतर हैं क्योंकि वे दिमागी सेट को कमजोर करते हैं 'चेतावनियों के बिना संकलन अच्छा है'। संकलक आपूर्तिकर्ता को एक बग की रिपोर्ट करें। –

+0

@ जोनाथन लेफ्लर मैंने कुछ साल पहले ही इस बग की सूचना दी है। यकीन नहीं है कि यह अभी भी है। विवरण के लिए मेरा जवाब देखें। – Lundin

3

यह विशेष चेतावनी सभी कोडेवायरियर कंपाइलरों में एक ज्ञात बग है। डेटा चेतावनी का संभावित नुकसान असंगत और छोटी गाड़ी है। कभी-कभी यह चेतावनी देता है क्योंकि निहित प्रकार के प्रचार का जोखिम होता है, कभी-कभी ऐसा नहीं होता है। this discussion देखें। मैं पुष्टि कर सकता हूं कि यह एस 12 सी के लिए सीडब्ल्यू के लिए भी सच है (कम से कम संस्करण 5.1 तक, जो मैं उपयोग कर रहा हूं)।

आप इस चेतावनी को अक्षम कर सकते हैं, लेकिन मैं इसकी अनुशंसा नहीं करता, क्योंकि इसे कभी-कभी झूठी चेतावनियों के साथ खतरनाक कोड मिल जाता है। आपके विशिष्ट मामले में: चेतावनी सही है।

आप स्पष्ट पूर्ण जानवरों के बिना छोटे पूर्णांक प्रकारों पर अंकगणित कर रहे हैं। ऐसा कोड खतरनाक है और संभवतः छिपी हुई बग्स हैं, क्योंकि सी हस्ताक्षरित इंकों के लिए छोटे पूर्णांक को बढ़ावा देता है। एमआईएसआरए-सी जैसे कोडिंग मानक, जो स्पष्ट जानवरों को लागू करता है, ने यहां मदद की होगी।

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

इसलिए मैं करने के लिए कोड बदलने का सुझाव होगा:

tfront = (byte)(tfront % tsize); 
... 

if((byte)(tfront +1) >= tsize) 
{ 
    tfront = 0; 
} 
else 
{ 
    tfront++; 
} 
+0

मैं आपके '(बाइट) (tfront +1)> = tsize' सुझाव से आश्वस्त नहीं हूं। प्रश्न में मूल स्थिति से अलग होने का एकमात्र मौका यह है कि यदि '(बाइट) (ट्वेंफ़ +1)' 'tfront + 1' से अलग है, और जब यह है, तो आपकी सुझाई गई स्थिति का नतीजा शायद नहीं है प्रोग्रामर क्या इरादा है।क्या आप वाकई संकलक चेतावनी विचारों को नहीं दे रहे हैं जिससे आप एक बग में डाल सकें जहां आम तौर पर कोई नहीं होता? यदि आप प्रकारों से मिलान करना चाहते हैं, तो '(हस्ताक्षरित int) tfront +1> = (हस्ताक्षरित int) tsize' शायद बेहतर है। –

+0

@PascalCuoq हाँ उस विशेष पंक्ति पर कास्ट कुछ हद तक picky है, यह केवल कुछ दुर्लभ मामले में परेशानी का कारण होगा जैसे 'tfront = 255'। शून्य से लपेटें, बिना हस्ताक्षर किए गए चर के लिए अच्छी तरह से परिभाषित किया गया है, इसलिए यदि प्रोग्रामर ने उस व्यवहार पर निर्भर कोड लिखा है, तो यह अपेक्षित रूप से काम नहीं करेगा क्योंकि 'टर्फ' को पूरी तरह से बढ़ावा दिया जाता है। अंतर्निहित पदोन्नति से संबंधित बग और विषमता की समस्या हमेशा यही है: प्रोग्रामर वास्तव में क्या इरादा रखता था? क्या वे अजीब होने की उम्मीद करते थे या क्या यह उनके आश्चर्य के रूप में आता है? ऐसे मामलों में कोड में टिप्पणियां रखना बहुत महत्वपूर्ण है। – Lundin

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