8-बिट एमसीयू पर सी इंटेगर प्रमोशन


14

उदाहरण के रूप में avr-gcc का उपयोग करते हुए, इंट प्रकार 16-बिट्स विस्तृत होने के लिए निर्दिष्ट हैं। सी में पूर्णांक प्रचार के कारण उन ऑपरेंडों में सी-परिणाम में 8-बिट ऑपरेंड्स को 16-बिट इंटों में परिवर्तित किया जा रहा है, इसका मतलब यह है कि एवीआर पर सभी 8-बिट अंकगणितीय ऑपरेशन को सी की तुलना में लिखे जाने में अधिक समय लगेगा। यदि सी के पूर्णांक पदोन्नति के कारण विधानसभा में लिखा गया है?


1
मुझे ऐसा नहीं लगता, कंपाइलर को एहसास होगा कि डेस्टिनेशन वैरिएबल (अहस्ताक्षरित) चार है, इसलिए यह टॉप 8 बिट्स की गणना करने में परेशान नहीं करेगा। फिर भी, मैंने पाया कि जीसीसी कभी-कभी अनुकूलन कोड में इतना अच्छा नहीं होता है, इसलिए यदि आप एएसएम में कोड करते हैं, तो परिणाम एमजीआईएचटी तेज हो सकता है। हालाँकि, जब तक आप बहुत मजबूत बजट अवरोधों के साथ बहुत महत्वपूर्ण समय / महत्वपूर्ण कार्य / इंटरट्रैप नहीं कर रहे हैं, तब या तो आपको एक अधिक शक्तिशाली प्रोसेसर का चयन करना चाहिए और इसे C में प्रोग्राम करना चाहिए, या बस निचले प्रदर्शन की चिंता नहीं करनी चाहिए (इसके बजाय समय पर विचार करें) -to- बाजार, बेहतर कोड पठनीयता / पुन: प्रयोज्य, कम बग, ecc ..)।
अगली hack

मैं जाँच के लिए समय नहीं होने के लिए माफी माँगता हूँ। हालाँकि, मुझे लगता है कि gcc के लिए एक कमांड-लाइन ध्वज था जो 'पूर्णांक संवर्धन' को नियंत्रित करेगा। कोड के विशिष्ट टुकड़ों के लिए इसे नियंत्रित करने के लिए शायद एक प्रज्ञा भी है। प्रदर्शन कितना महत्वपूर्ण है? एक AVR के बहुत सारे उपयोगों में, कुछ अंकगणित की गति में अंतर कोई मुद्दा नहीं है। पहले कोड को सही ढंग से काम करने पर फॉक्स। फिर अगर कोई प्रदर्शन मुद्दा है, तो पता करें कि यह क्या है। असेंबलर में समय कोडिंग को बर्बाद करना आसान होगा, केवल यो यह नहीं मिला।
gbulmer

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

3
याद रखें: टिप्पणियों में सवालों के जवाब देने से बचें।
पाइप

4
इस तरह के सवाल एसओ पर सी विशेषज्ञों से पूछना बेहतर है, क्योंकि यह एक शुद्ध सॉफ्टवेयर प्रश्न है। सी में पूर्णांक संवर्धन कुछ जटिल विषय है - औसत सी प्रोग्रामर के बारे में बहुत सारी गलत धारणाएँ होंगी।
लुंडिन

जवाबों:


16

कहानी संक्षिप्त में:

16 बिट्स को पूर्णांक पदोन्नति हमेशा होती है - सी मानक इसे लागू करता है। लेकिन कंपाइलर को गणना को 8 बिट्स तक वापस ऑप्टिमाइज़ करने की अनुमति है (एम्बेडेड सिस्टम कंपाइलर्स आमतौर पर ऐसे ऑप्टिमाइज़ेशन पर बहुत अच्छे होते हैं), यदि यह यह कटौती कर सकता है कि साइन वैसा ही होगा जैसा कि टाइप का प्रचार किया गया था।

ऐसी स्थिति हर बार नहीं होती है! पूर्णांक पदोन्नति के कारण निहित हस्ताक्षर परिवर्तन एम्बेडेड सिस्टम में बग का एक सामान्य स्रोत हैं।

विस्तृत विवरण यहां पाया जा सकता है: लागू प्रकार के प्रचार नियम


8
unsigned int fun1 ( unsigned int a, unsigned int b )
{
    return(a+b);
}

unsigned char fun2 ( unsigned int a, unsigned int b )
{
    return(a+b);
}

unsigned int fun3 ( unsigned char a, unsigned char b )
{
    return(a+b);
}

unsigned char fun4 ( unsigned char a, unsigned char b )
{
    return(a+b);
}

उम्मीद के मुताबिक fun1 सभी इन्ट्स है इसलिए 16 बिट गणित करता है

00000000 <fun1>:
   0:   86 0f           add r24, r22
   2:   97 1f           adc r25, r23
   4:   08 95           ret

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

00000006 <fun2>:
   6:   86 0f           add r24, r22
   8:   08 95           ret

वास्तव में यहां आश्चर्य नहीं कि पदोन्नति होती है, संकलक ऐसा नहीं करते थे, यह सुनिश्चित नहीं करते थे कि यह संस्करण क्या शुरू कर रहा है, यह मेरे कैरियर में जल्दी शुरू हुआ और संकलक आदेश (ऊपर की तरह) को बढ़ावा देने के बावजूद, भले ही मैं पदोन्नति कर रहा हूं इसे uchar गणित करने के लिए कहा, आश्चर्य नहीं।

0000000a <fun3>:
   a:   70 e0           ldi r23, 0x00   ; 0
   c:   26 2f           mov r18, r22
   e:   37 2f           mov r19, r23
  10:   28 0f           add r18, r24
  12:   31 1d           adc r19, r1
  14:   82 2f           mov r24, r18
  16:   93 2f           mov r25, r19
  18:   08 95           ret

और आदर्श, मुझे पता है कि यह 8 बिट है, एक 8 बिट परिणाम चाहते हैं इसलिए मैंने इसे 8 बिट के माध्यम से सभी तरह से करने के लिए कहा।

0000001a <fun4>:
  1a:   86 0f           add r24, r22
  1c:   08 95           ret

तो सामान्य तौर पर रजिस्टर आकार के लिए लक्ष्य बनाना बेहतर होता है, जो आदर्श रूप से एक (यू) इंट का आकार है, 8 बिट mcu के लिए इस तरह के संकलक लेखकों को एक समझौता करना था ... प्वाइंट न होना एक आदत बनाना गणित के लिए uchar का उपयोग करना जिसे आप जानते हैं कि 8 बिट से अधिक की आवश्यकता है जब आप उस कोड को स्थानांतरित करते हैं या नए कोड लिखते हैं जैसे कि बड़े रजिस्टरों वाले प्रोसेसर पर अब संकलक को मास्किंग शुरू करना होगा और विस्तार करना होगा, जो कुछ निर्देशों में मूल रूप से करते हैं। और दूसरों को नहीं।

00000000 <fun1>:
   0:   e0800001    add r0, r0, r1
   4:   e12fff1e    bx  lr

00000008 <fun2>:
   8:   e0800001    add r0, r0, r1
   c:   e20000ff    and r0, r0, #255    ; 0xff
  10:   e12fff1e    bx  lr

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

EDIT टिप्पणियों की चर्चा पर आधारित है

unsigned int fun ( unsigned char a, unsigned char b )
{
    unsigned int c;
    c = (a<<8)|b;
    return(c);
}

00000000 <fun>:
   0:   70 e0           ldi r23, 0x00   ; 0
   2:   26 2f           mov r18, r22
   4:   37 2f           mov r19, r23
   6:   38 2b           or  r19, r24
   8:   82 2f           mov r24, r18
   a:   93 2f           mov r25, r19
   c:   08 95           ret

00000000 <fun>:
   0:   e1810400    orr r0, r1, r0, lsl #8
   4:   e12fff1e    bx  lr

कोई आश्चर्य नहीं। यद्यपि ऑप्टिमाइज़र ने उस अतिरिक्त निर्देश को क्यों छोड़ दिया, क्या आप r19 पर ldi का उपयोग नहीं कर सकते हैं? (जब मैंने पूछा तो मुझे इसका जवाब पता था)।

EDIT2

avr के लिए

avr-gcc --version
avr-gcc (GCC) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

बुरी आदत से बचने या 8 बिट तुलना करने के लिए नहीं

arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

स्पष्ट रूप से अनुकूलन केवल अपने ही संकलक के साथ प्रयास करने के लिए एक सेकंड में था यह देखने के लिए कि यह मेरे आउटपुट की तुलना कैसे करता है, लेकिन वैसे भी:

whatever-gcc -O2 -c so.c -o so.o
whatever-objdump -D so.o

और हाँ, बाइट आकार के चर के लिए बाइट्स का उपयोग करना, निश्चित रूप से एक avr, pic, आदि पर, आपको मेमोरी को बचाएगा और आप वास्तव में इसे संरक्षित करने का प्रयास करना चाहते हैं ... यदि आप वास्तव में इसका उपयोग कर रहे हैं, लेकिन जैसा कि यहाँ दिखाया गया है जितना संभव हो उतना कम है। स्मृति में जा रहा है, जितना संभव हो उतना रजिस्टरों में, इसलिए फ्लैश बचत अतिरिक्त चर नहीं होने से आती है, राम बचत वास्तविक हो सकती है या नहीं हो सकती है।


2
"संकलक ने यह सुनिश्चित करने के लिए उपयोग नहीं किया कि यह संस्करण क्या शुरू कर रहा है, यह मेरे करियर की शुरुआत में चला गया और संकलक आदेश से बाहर (सिर्फ ऊपर की तरह) को बढ़ावा देने के बावजूद, पदोन्नति करते हुए भी मैंने इसे uchar गणित करने के लिए कहा, आश्चर्य नहीं था।" यह क्योंकि एम्बेडेड सिस्टम सी compilers भयानक मानक अनुरूपता के लिए प्रयोग किया जाता है :) संकलक आमतौर पर अनुकूलन करने के लिए अनुमति दी है, लेकिन यहाँ यह घटा नहीं कर सकता कि परिणाम एक में फिट होगा unsigned charतो यह है के रूप में आवश्यक 16 बिट करने के लिए बढ़ावा देने के प्रदर्शन करने के लिए, मानक द्वारा।
लुंडिन

1
@old_timer (a<<8)|bहमेशा किसी भी सिस्टम के लिए गलत है जहां int16 बिट्स है। जिस पर हस्ताक्षर किए गए हैं, उसका aप्रचार किया जाएगा int। यदि aMSB में कोई मान रखा जाता है, तो आप उस डेटा को 16 बिट संख्या के साइन बिट में शिफ्ट करते हैं, जो अपरिभाषित व्यवहार को आमंत्रित करता है।
लंडिन

1
fun3 मजेदार है..है ... कंपाइलर द्वारा पूरी तरह से अनधिकृत ... माना जाता है कि R1 हमेशा GCC में 0 होता है, और r, rb, {rh, rl} को इंगित करता है, चर a, b और परिणाम के लिए रजिस्टर करता है, संकलक कर सकता था: 1) mov rh, r1; 2) Mov आरएल, आरए; 2) आरएल, आरबी जोड़ें; 3) एडीसी आरएच, आरएच; 4) रिटायर। 4 निर्देश, बनाम 7 या 8 ... निर्देश 1 को ldi rh, 0 में बदला जा सकता है।
अगली

1
यह एक बेहतर उत्तर होगा यदि यह उपयोग में संकलक और प्रासंगिक विकल्प निर्दिष्ट करता है।
रसेल बोरोगोव

1
Int / char आदि का उपयोग करने से बचने के लिए यह एक अच्छा विचार है और इसके बजाय अधिक स्पष्ट और पठनीय int16_t और int8_t का उपयोग करें।
उपयोगकर्ता

7

जरूरी नहीं है, क्योंकि आधुनिक संकलक उत्पन्न कोड के अनुकूलन में अच्छा काम करते हैं। उदाहरण के लिए, यदि आप लिखते हैं z = x + y;कि सभी चर कहाँ हैं unsigned char, unsigned intतो गणना करने से पहले संकलक को उन्हें बढ़ावा देना आवश्यक है । हालांकि, चूंकि अंतिम परिणाम प्रचार के बिना बिल्कुल समान होगा, इसलिए कंपाइलर कोड उत्पन्न करेगा जो सिर्फ 8-बिट चर जोड़ता है।

बेशक, यह हमेशा मामला नहीं होता है, उदाहरण के लिए परिणाम का परिणाम z = (x + y)/2;ऊपरी बाइट पर निर्भर करेगा, इसलिए पदोन्नति होगी। इंटरमीडिएट के रिजल्ट को कास्ट करके विधानसभा का सहारा लिए बिना इसे अभी भी टाला जा सकता है unsigned char

संकलक विकल्पों का उपयोग करके ऐसी कुछ अक्षमताओं से बचा जा सकता है। उदाहरण के लिए, कई 8-बिट संकलक के पास intसी द्वारा आवश्यक के बजाय 1 बाइट में फिट होने वाले प्रकारों में फिट होने के लिए एक व्यावहारिक या एक कमांड-लाइन स्विच है।


4
"संकलित int को बढ़ावा देने के लिए संकलक की आवश्यकता है"। नहीं, संकलक को उन्हें बढ़ावा देने की आवश्यकता है int, क्योंकि किसी भी प्लेटफ़ॉर्म पर charसमान रूपांतरण रैंक नहीं होगी int
लुंडिन

3
"उदाहरण के लिए, कई 8-बिट संकलक में 1 बाइट में फिटन प्रकारों को फिट करने के लिए सी के रूप में आवश्यक के बजाय एक व्यावहारिक या एक कमांड-लाइन स्विच है।" सी मानक 1 बाइट में गणना करने योग्य चरों को आवंटित करने की अनुमति देता है। इसके लिए केवल यह आवश्यक है कि एन्यूमरेशन स्थिरांक होना चाहिए int(हाँ यह असंगत है)। C11 6.7.2.2Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined...
लुंडिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.