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, आदि पर, आपको मेमोरी को बचाएगा और आप वास्तव में इसे संरक्षित करने का प्रयास करना चाहते हैं ... यदि आप वास्तव में इसका उपयोग कर रहे हैं, लेकिन जैसा कि यहाँ दिखाया गया है जितना संभव हो उतना कम है। स्मृति में जा रहा है, जितना संभव हो उतना रजिस्टरों में, इसलिए फ्लैश बचत अतिरिक्त चर नहीं होने से आती है, राम बचत वास्तविक हो सकती है या नहीं हो सकती है।