Am Beispiel von avr-gcc wird für int-Typen eine Breite von 16 Bit angegeben. Das Ausführen von Operationen mit 8-Bit-Operanden in C führt dazu, dass diese Operanden aufgrund der Ganzzahl-Heraufstufung in C in 16-Bit-Int-Typen konvertiert werden. Bedeutet dies, dass alle 8-Bit-Arithmetikoperationen auf einem AVR viel länger dauern, wenn sie in C geschrieben werden Wenn in Assembly aufgrund der ganzzahligen Promotion von C geschrieben?
microcontroller
avr
c
pr871
quelle
quelle
Antworten:
Um es kurz zu machen:
Die ganzzahlige Heraufstufung auf 16 Bit findet immer statt - der C-Standard erzwingt dies. Der Compiler kann die Berechnung jedoch wieder auf 8 Bit optimieren (eingebettete System-Compiler sind normalerweise bei solchen Optimierungen ziemlich gut), wenn sich daraus ergibt, dass das Vorzeichen das gleiche ist, wie es gewesen wäre, wenn der Typ heraufgestuft worden wäre.
Dies ist nicht immer der Fall! Implizite Signifikanzänderungen, die durch die Heraufstufung von Ganzzahlen verursacht werden, sind eine häufige Fehlerquelle in eingebetteten Systemen.
Eine ausführliche Erklärung finden Sie hier: Regeln für die implizite Typheraufstufung .
quelle
Wie erwartet ist fun1 alles in allem, ebenso die 16-Bit-Mathematik
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.
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.
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.
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.
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
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
um die schlechte Angewohnheit oder nicht 8-Bit-Vergleich zu vermeiden
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:
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.
quelle
unsigned char
damit es hat die Förderung auf 16 Bit durchzuführen, je nach Bedarf nach dem Standard.(a<<8)|b
ist immer falsch für ein System mitint
16 Bit.a
wird implizit befördert, zuint
dem signiert wird. Fallsa
ein Wert im MSB enthalten ist, verschieben Sie diese Daten letztendlich in das Vorzeichenbit einer 16-Bit-Zahl, wodurch undefiniertes Verhalten ausgelöst wird.Nicht unbedingt, da moderne Compiler einen guten Job bei der Optimierung des generierten Codes machen. Wenn Sie beispielsweise schreiben,
z = x + y;
wo sich alle Variablen befindenunsigned char
, muss der Compiler sie heraufstufen,unsigned int
bevor Sie die Berechnungen ausführen. Da jedoch das Endergebnis ohne die Heraufstufung genau dasselbe ist, generiert der Compiler Code, der lediglich 8-Bit-Variablen hinzufügt.Dies ist natürlich nicht immer der Fall, zum Beispiel würde das Ergebnis von
z = (x + y)/2;
vom oberen Byte abhängen, so dass eine Heraufstufung stattfinden wird. Es kann dennoch vermieden werden, ohne auf die Montage zurückzugreifen, indem das Zwischenergebnis auf zurückgegossen wirdunsigned char
.Einige dieser Ineffizienzen können mit Compiler-Optionen vermieden werden. Beispielsweise verfügen viele 8-Bit-Compiler über ein Pragma oder eine Befehlszeilenoption, um die Aufzählungstypen auf 1 Byte anzupassen, anstatt
int
wie von C gefordert.quelle
int
, dachar
sie höchstwahrscheinlich nicht den gleichen Conversion-Rang wieint
auf einer Plattform haben.int
(ja, es ist inkonsistent). 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...