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);
}
Wie erwartet ist fun1 alles in allem, ebenso die 16-Bit-Mathematik
00000000 <fun1>:
0: 86 0f add r24, r22
2: 97 1f adc r25, r23
4: 08 95 ret
Obwohl technisch nicht korrekt, da es sich um eine 16-Bit-Addition handelt, die vom Code aufgerufen wird, entfernte dieser Compiler den ADC aufgrund der Ergebnisgröße, auch wenn er nicht optimiert war.
00000006 <fun2>:
6: 86 0f add r24, r22
8: 08 95 ret
Nicht wirklich überrascht, dass hier die Promotion stattfindet. Früher haben Compiler dies nicht getan. Sie waren sich nicht sicher, in welcher Version dieser Start stattgefunden hat. Sie sind zu Beginn meiner Karriere darauf gestoßen, und obwohl die Compiler nicht in der richtigen Reihenfolge promoten (genau wie oben), haben sie die Promotion durchgeführt, obwohl ich sagte ihm, er solle uchar rechnen, nicht überrascht.
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
und das Ideal, ich weiß, es ist 8-Bit, möchte ein 8-Bit-Ergebnis, also habe ich ihm einfach gesagt, dass er 8-Bit durchziehen soll.
0000001a <fun4>:
1a: 86 0f add r24, r22
1c: 08 95 ret
Im Allgemeinen ist es also besser, die Registergröße anzustreben, die idealerweise der Größe eines (u) int entspricht. Für eine 8-Bit-CPU wie diese mussten die Compiler-Autoren einen Kompromiss eingehen Wenn Sie uchar für Mathematik verwenden, von dem Sie wissen, dass es nicht mehr als 8 Bit benötigt, als wenn Sie diesen Code verschieben oder neuen Code wie diesen auf einen Prozessor mit größeren Registern schreiben, muss der Compiler jetzt mit dem Maskieren und Erweitern von Zeichen beginnen, was einige in einigen Anweisungen nativ tun. und andere nicht.
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 Bit zu erzwingen kostet mehr. Ich habe ein bisschen / viel geschummelt, würde etwas kompliziertere Beispiele brauchen, um mehr davon auf faire Weise zu sehen.
BEARBEITEN basierend auf Kommentardiskussion
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
keine Überraschung. Obwohl der Optimierer diese zusätzliche Anweisung verlassen hat, können Sie ldi auf r19 nicht verwenden? (Ich wusste die Antwort, als ich sie fragte).
EDIT2
für 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.
um die schlechte Angewohnheit oder nicht 8-Bit-Vergleich zu vermeiden
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.
Offensichtlich dauerte die Optimierung nur eine Sekunde, um mit Ihrem eigenen Compiler zu versuchen, zu sehen, wie sie mit meiner Ausgabe verglichen werden kann, aber trotzdem:
whatever-gcc -O2 -c so.c -o so.o
whatever-objdump -D so.o
Und ja, die Verwendung von Bytes für Variablen mit Byte-Größe, sicherlich auf einem AVR, einem Bild usw., spart Speicher und Sie möchten wirklich versuchen, ihn zu erhalten ... wenn Sie ihn tatsächlich verwenden, aber wie hier gezeigt, ist dies so wenig wie möglich Wird im Speicher gespeichert, so viel wie möglich in den Registern, so dass die Flash-Einsparungen dadurch erzielt werden, dass keine zusätzlichen Variablen vorhanden sind. Die RAM-Einsparungen können real sein oder auch nicht.