2009-04-26 18 views
6

मैं निम्नलिखित सी कोड है:सी भाषा: #DEFINEd मान 8-बिट गुणा को गड़बड़ करता है। क्यूं कर?

#define PRR_SCALE 255 
... 
uint8_t a = 3; 
uint8_t b = 4; 
uint8_t prr; 
prr = (PRR_SCALE * a)/b; 
printf("prr: %u\n", prr); 

यदि मैं यह संकलन (एक msp430 मंच संकलक का उपयोग कर, एक छोटा सा एम्बेडेड ओएस के लिए contiki कहा जाता है), जबकि मैं उम्मीद 191. (uint8_t typedef है 'परिणाम 0 है एक अहस्ताक्षरित चार)

के रूप में एड अगर मैं के लिए इसे बदल:

uint8_t a = 3; 
uint8_t b = 4; 
uint8_t c = 255; 
uint8_t prr; 
prr = (c * a)/b; 
printf("prr: %u\n", prr); 

इसे सही ढंग से काम करता है और प्रिंट 191.

01,235,

उबंटू बॉक्स पर जीसीसी का उपयोग करके इस 'सामान्य' के एक साधारण संस्करण को संकलित करना दोनों मामलों में सही मूल्य प्रिंट करता है।

मुझे बिल्कुल यकीन नहीं है कि यह क्यों है। मैं पहले से एक चर के लिए DEFINED मान निर्दिष्ट करके इसे बाधित कर सकता हूं, लेकिन मैं ऐसा नहीं करता।

क्या कोई जानता है कि यह क्यों है? शायद इसके बारे में कुछ और जानकारी के लिंक के साथ?

+0

मैं निश्चित रूप से दोनों को 1 9 1 प्रिंट करने की उम्मीद करता हूं। दूसरे मामले में, पहले सी और ए को स्वतंत्र रूप से int में प्रचारित किया जाता है और इसलिए उनका गुणा अधिक नहीं हो सकता है। पहले मामले में भी ऐसा ही होता है (हालांकि वहां, PRR_SCALE पहले से ही int है - लेकिन इससे इंट को बढ़ावा देने में कोई बदलाव नहीं आएगा)। आपके बॉक्स पर आपका जीसीसी बिल्कुल ठीक व्यवहार करता है। –

+0

जांचें कि आपके पास हेडर stdio.h शामिल है। मुझे पता है कि msp430 के लिए एक कंपाइलर अंतर्निहित फ़ंक्शन घोषणाओं को होने की अनुमति देता है: यदि ऐसा है, तो printf को कॉल अपरिभाषित व्यवहार का कारण बनता है, और "0" परिणाम इस प्रकार समझाया जाएगा। केवल मेरे दो सेंट्स। ऐसा नहीं लगता कि यह एक उत्तर के लायक है :) –

+0

@litb: stdio.h शामिल है। – Rabarberski

उत्तर

10

संक्षिप्त उत्तर: आप कंपाइलर छोटी है। (ओवरफ्लो के साथ कोई समस्या नहीं है, जैसा कि अन्य ने सुझाव दिया है।)

दोनों मामलों में, अंकगणित int में किया जाता है, जो कम से कम 16 बिट लंबे होने की गारंटी है। पूर्व स्निपेट में ऐसा इसलिए है क्योंकि 255int है, बाद में यह integral promotion की वजह से है।

जैसा कि आपने देखा है, जीसीसी इसे सही तरीके से संभालती है।

+0

"अंकगणित int में किया जाता है, जिसे कम से कम 16-बिट लंबा होने की गारंटी दी जाती है" - क्या आप उस पर एक स्रोत प्रदान कर सकते हैं? मैं इसकी वैधता पर सवाल करता हूं ... – strager

+1

"अंकगणितीय int में किया जाता है": अभिन्न पदोन्नति का परिणाम। "[int] कम से कम 16-बिट लंबा होने की गारंटी है": अप्रत्यक्ष रूप से गारंटीकृत, INT_MAX कम से कम 32767 और INT_MIN होना चाहिए -32767 (मानक में सीमा.h के बारे में अनुभाग देखें)। – avakar

+0

+1, जो कुछ मुझे डीबग करने के बाद अपेक्षित था। क्या आप एक लिंक प्रदान कर सकते हैं जो निर्दिष्ट करता है कि मूल्य वापस कैसे परिवर्तित किया जाता है? या यह सिर्फ मॉड्यूलर अंकगणित है? – JaredPar

2

255 को एक पूर्णांक अक्षर के रूप में संसाधित किया जा रहा है और पूरी अभिव्यक्ति को हस्ताक्षरित चार आधारित के बजाय int आधारित होने का कारण बनता है। दूसरा मामला इस प्रकार को सही होने के लिए मजबूर करता है। अपने #define बदलते इस प्रकार का प्रयास करें:

#define PRR_SCALE ((uint8_t) 255) 
+0

काम नहीं करता है, मैंने पहले से ही कोशिश की थी (ठीक है, मैंने कास्ट किया सीधे गणना रेखा में। मैंने सुझाव दिया जैसा आपने सुझाव दिया था। कोई फर्क नहीं पड़ता)। – Rabarberski

+0

मैं दोनों कोड उदाहरण, अंकगणित int में किया जाता है।यह पूर्णांक पदोन्नति के कारण है, http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf, खंड 6.3.1.1, अनुच्छेद 2. –

1

मुझे यकीन है कि नहीं कर रहा हूँ क्यों परिभाषित काम नहीं करता है, लेकिन आप uint8_t चर के साथ रोलओवर में चल रहा हो सकता है। 255 uint8_t (2^8 - 1) के लिए अधिकतम मान है, इसलिए यदि आप इसे 3 से गुणा करते हैं, तो आप कुछ सूक्ष्म रोलओवर समस्याओं में भागने के लिए बाध्य हैं।

कंपाइलर आपके कोड को अनुकूलित कर सकता है, और आपके गणित अभिव्यक्ति के परिणाम की पूर्व-गणना कर रहा है और परिणाम को prr में बदल रहा है (क्योंकि यह फिट बैठता है, भले ही मध्यवर्ती मान फिट न हो)।

चेक क्या हुआ अगर (इससे आप क्या चाहते हैं की तरह व्यवहार नहीं होगा) इस तरह से अपनी अभिव्यक्ति को तोड़ने होता है:

prr = c * a; // rollover! 
prr = prr/b; 

तुम सिर्फ एक बड़ा डेटाप्रकार उपयोग करने की आवश्यकता हो सकती है।

+1

तकनीकी रूप से c * a नहीं है अतिप्रवाह। सी मानक निर्दिष्ट करता है कि हस्ताक्षर किए गए पूर्णांक प्रकारों के लिए ओवरफ़्लो नहीं हो सकता है। – JaredPar

+0

कूल, यह समझ में आता है। मुझे लगता है कि "रोलओवर" एक बेहतर शब्द होगा। –

0

एक अंतर यह मैं मामले -1 में सोच सकते हैं,

PRR_SCALE शाब्दिक मूल्य ROM या कोड क्षेत्र में जा सकते हैं। और एमयूएल ओपेकोड में कुछ अंतर हो सकता है,

case-1: [register], [rom] 
case -2: [register], [register] 

यह बिल्कुल समझ में नहीं आता है।

2

यदि प्रश्न में संकलक mspgcc है, तो इसे संकलित प्रोग्राम की एक असेंबलर सूची को बाइनरी/हेक्स फ़ाइल के साथ एक साथ रखना चाहिए। अन्य कंपाइलरों को ऐसा करने के लिए अतिरिक्त कंपाइलर झंडे की आवश्यकता हो सकती है। या शायद बाइनरी पर एक अलग डिस्सेबलर भी चलाया जा सकता है।

यह जगह एक विवरण देखने के लिए जहां है। संकलक अनुकूलन करने के लिए कारण, वास्तविक प्रोसेसर के समक्ष प्रस्तुत कोड मूल सी कोड के लिए नहीं बहुत समानता हो सकता है (लेकिन आम तौर पर एक ही काम करता है)।

दोषपूर्ण कोड का प्रतिनिधित्व करने वाले कुछ असेंबलर निर्देशों के माध्यम से कदम उठाने से समस्या का कारण प्रकट होना चाहिए।

मेरा अनुमान है कि संकलक किसी भी तरह से पूरी गणना को अनुकूलित करता है परिभाषित स्थिरता संकलन समय पर एक ज्ञात हिस्सा है। 255 * एक्स को x < < 8-x (जो तेज़ और छोटा है) अनुकूलित अनुकूलित असेंबलर कोड के साथ कुछ गलत हो रहा है।

मैं अपने सिस्टम पर दोनों संस्करणों को संकलित करने के समय लगा। सक्रिय अनुकूलन के साथ, mspgcc निम्नलिखित कोड का उत्पादन:

#define PRR_SCALE 255 
uint8_t a = 3; 
uint8_t b = 4; 
uint8_t prr; 
prr = (PRR_SCALE * a)/b; 
    40ce: 3c 40 fd ff  mov #-3, r12 ;#0xfffd 
    40d2: 2a 42   mov #4, r10 ;r2 As==10 
    40d4: b0 12 fa 6f  call __divmodhi4 ;#0x6ffa 
    40d8: 0f 4c   mov r12, r15 ; 
printf("prr: %u\n", prr); 
    40da: 7f f3   and.b #-1, r15 ;r3 As==11 
    40dc: 0f 12   push r15  ; 
    40de: 30 12 c0 40  push #16576  ;#0x40c0 
    40e2: b0 12 9c 67  call printf  ;#0x679c 
    40e6: 21 52   add #4, r1 ;r2 As==10 

हम देख सकते हैं, संकलक सीधे 255 * करने के लिए -3 (0xfffd) 3 का परिणाम गणना करता है। और यहाँ समस्या है। किसी भी तरह 255 को 255 हस्ताक्षरित 16 बिट के बजाय -1-हस्ताक्षरित 8-बिट के रूप में व्याख्या किया जाता है। या इसे पहले 8 बिट तक पार्स किया गया है और फिर 16 बिट तक साइन-विस्तार किया गया है। जो कुछ भी।

इस विषय पर एक चर्चा mspgcc मेलिंग सूची में पहले ही शुरू हो चुकी है।