(→Siehe auch) |
|||
Zeile 302: | Zeile 302: | ||
}} | }} | ||
+ | = Sortieren mit Bubble-Sort | ||
+ | |||
+ | Zum Abschluss noch ein komplexeres Beispiel: Ein Array mit 8-Bit-Werten soll mit Bubble-Sort der Größe nach sortiert werden. Im Array wird nach dem größten Wert gesucht und dieser ans Ende getauscht. Danach macht man den Teilbereich, in dem man das Maximum sucht, um 1 kleiner, bis man fertig ist. Die größten Zahlen wandern wie Blasen nach oben, daher der Name ''Bubble-Sort'' für diesen Sortier-Algorithmus. | ||
+ | |||
+ | Variablen: | ||
+ | * <tt>n</tt> Array-Größe | ||
+ | * <tt>a</tt> das Array | ||
+ | * <tt>i</tt> Größe der Teilbereichs | ||
+ | * <tt>j</tt> Laufvariable durch den Teilbereich | ||
+ | |||
+ | '''Quellcodes:''' | ||
+ | |||
+ | {{Codevergleich|avr-gcc|BASCOM | ||
+ | | | ||
+ | <pre> | ||
+ | #include <limits.h> | ||
+ | #include <inttypes.h> | ||
+ | |||
+ | void | ||
+ | bubble_sort (uint8_t n, char * a) | ||
+ | { | ||
+ | uint8_t i; | ||
+ | |||
+ | // Bereich schrumpft von n auf 2 | ||
+ | for (i = n; i >= 2; i--) | ||
+ | { | ||
+ | char max = CHAR_MIN; | ||
+ | uint8_t j, j_max; | ||
+ | |||
+ | // im Bereich nach MAX suchen | ||
+ | for (j = 0; j < i; j++) | ||
+ | { | ||
+ | if (a[j] >= max) | ||
+ | { | ||
+ | // MAX und Pos. merken | ||
+ | j_max = j; | ||
+ | max = a[j_max]; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // MAX ans Ende tauschen | ||
+ | a[j_max] = a[i-1]; | ||
+ | a[i-1] = max; | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | | | ||
+ | <pre> | ||
+ | </pre> | ||
+ | }} | ||
+ | |||
+ | '''Compilat:''' | ||
+ | |||
+ | {{Codevergleich|avr-gcc|BASCOM | ||
+ | | | ||
+ | <pre> | ||
+ | bubble_sort: | ||
+ | cpi r24,2 ; i >= 2 | ||
+ | brlo .L12 | ||
+ | movw r26,r22 ; $6 = a | ||
+ | add r26,r24 ; $6 += i | ||
+ | adc r27,__zero_reg__ | ||
+ | sbiw r26,1 ; $6-- | ||
+ | .L10: ; { i | ||
+ | ldi r20,-128 ; max = -128 | ||
+ | ldi r19,0 ; j = 0 | ||
+ | cp r19,r24 ; j < i | ||
+ | brsh .L14 | ||
+ | movw r30,r22 ; $3 = a | ||
+ | .L9: ; { j | ||
+ | ld r18,Z+ ; $4 = * $3++ | ||
+ | cp r18,r20 ; $4 >= max | ||
+ | brlt .L7 { | ||
+ | mov r21,r19 ; j_max = j | ||
+ | mov r20,r18 ; max = $4 | ||
+ | .L7: } | ||
+ | subi r19,-1 ; j++ | ||
+ | cp r19,r24 ; j < i | ||
+ | brlo .L9 | ||
+ | .L14: ; } j | ||
+ | movw r30,r22 ; $5 = a | ||
+ | add r30,r21 ; $5 += j_max | ||
+ | adc r31,__zero_reg__ | ||
+ | ld r18,X ; $7 = * $6 | ||
+ | st Z,r18 ; * $5 = $7 | ||
+ | st X,r20 ; * $6 = max | ||
+ | subi r24,1 ; i-- | ||
+ | sbiw r26,1 ; $6-- | ||
+ | cpi r24,2 ; i >= 2 | ||
+ | brsh .L10 | ||
+ | .L12: ; } i | ||
+ | ret | ||
+ | </pre> | ||
+ | | | ||
+ | <pre> | ||
+ | </pre> | ||
+ | }} | ||
+ | |||
+ | Die Codes wurden etwas nachkommentiert und -formatiert, um besser den Zusammenhang mit der Quelle durchblicken zu können. | ||
+ | |||
=Siehe auch= | =Siehe auch= | ||
* [[Sourcevergleich]] | * [[Sourcevergleich]] |
Version vom 6. April 2006, 21:21 Uhr
Ein wichtiges Merkmal eines Compilers ist die Güte des erzeugten Codes. Immerhin will man seine Hardware optimal nutzen, und die geschriebenen Programme sollen möglichst wenig Laufzeit brauchen und möglichst wenig Speicher – also RAM und Flash – belegen.
Ein Vergleich der erzeugten Codes ist jedoch nicht einfach, denn ein Problem kann bereits innerhalb ein und der selben Programmiersprache auf sehr unterschiedliche Art und Weisen formuliert oder gelöst werden.
Dieser Artikel versucht ansatzweise einen Codevergleich weit verbreiteter AVR-Compiler anhand sehr einfacher Aufgaben, die "geradeaus" und ohne Umschweife programmiert wurden.
Ein Vergleich der Programmierung von Hardware-Komponenten und Peripherie wie Timer-, UART- oder I2C-Module scheint dabei weniger interessant, denn obwohl die Codes zum Steuern dieser Komponente in unterschiedlichen Sprachen recht verschieden aussehen, werden sie doch auf die selben Maschinen-Codes abgebildet, die sich im wesentlichen auf das Setzen und Lesen von Registern (SFRs) reduzieren. Neben diesen für jedes Programm essenziellen Abschnitten, besteht ein Programm aber zum großen Teil aus hardwareunanhängigen Aufgaben wie Registerverwaltung, Funktionsaufrufen, Schleifen, Abfragen, etc.
Interessanter erscheint ein Vergleich einfacher Aufgaben, die erkennen lassen, wie gut ein Compiler in der Lage ist, die Ressourcen eines Mikrocontrollers zu nutzen bzw. zu schonen.
Inhaltsverzeichnis
Summe der ersten n Zahlen
Berechnet wird die Summe der ersten n Zahlen:
- [math] \operatorname{sum}(n) \,=\, \sum_{k=1}^n k \,=\, 1 + 2 + \ldots + n [/math]
Die Zahl n wird als 16-Bit Zahl angegeben und das Ergebnis als 16-Bit-Zahl berechnet. Ein eventueller Überlauf wird nicht beachtet.
Der Code wird jeweils als eigene Funktion implementiert, um Abhängigkeiten vom umliegenden Code zu vermeiden.
Für diese Berechnung gibt es mehrere Möglichkeiten.
Aufsummieren in einer Schleife
Quellcodes:
|
|
Compilat:
|
|
Berechnung mit rekursiver Funktion
Quellcodes:
|
|
Compilat:
|
|
Berechnung durch Formel
Quellcodes:
|
|
Compilat:
|
|
Interrupt-Routinen
Auch diese Beispiele machen nicht viel. Das erste zählt nur eine 16-Bit Variable hoch, das zweite macht nichts weiter, als ein Funktionsaufruf.
Eine Variable hochzählen
Quellcodes:
|
|
Compilat:
|
|
Eine Funktion aufrufen
Quellcodes:
|
|
Compilat:
|
|
= Sortieren mit Bubble-Sort
Zum Abschluss noch ein komplexeres Beispiel: Ein Array mit 8-Bit-Werten soll mit Bubble-Sort der Größe nach sortiert werden. Im Array wird nach dem größten Wert gesucht und dieser ans Ende getauscht. Danach macht man den Teilbereich, in dem man das Maximum sucht, um 1 kleiner, bis man fertig ist. Die größten Zahlen wandern wie Blasen nach oben, daher der Name Bubble-Sort für diesen Sortier-Algorithmus.
Variablen:
- n Array-Größe
- a das Array
- i Größe der Teilbereichs
- j Laufvariable durch den Teilbereich
Quellcodes:
|
|
Compilat:
|
|
Die Codes wurden etwas nachkommentiert und -formatiert, um besser den Zusammenhang mit der Quelle durchblicken zu können.