mikrocontroller.net

Forum: Compiler & IDEs Schieben mit unsigned char?


Autor: Manfred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
im ATMega8 beschäftige ich mich gerade mit dem USART. Da ist folgender
Beispielcode auf S. 145 angegeben:

unsigned int USART_Receive(void)
{
unsigned char status, resh, resl;
... bla
/*Filter the ninth bit, then return*/
resh = (resh >> 1) & 0x01;
return ((resh << 8) | resl);
}

1.) In der vorletzten Zeile wäre es doch auch Ressourcenschonender ohne
schieben gegangen, wenn man
resh = resh & 0x02;
geschrieben hätte?
2.) resh ist als unsigned char (8 Bit) deklariert. Wenn da jetzt ein 8
Bit Shift kommt, stehen doch nur noch Nullen da oder macht der Compiler
eine automatische Erweiterung auf 16 Bit, da der Returntyp 16 Bit ist?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu 1.:
Nein, denn das Bit muss ja auf das LSB verschoben werden, deshalb ist
die Schiebeoperation notwendig. Das neunte Bit steht nach dem Empfang
an der Stelle '1' im UCSRB, das in resh eingelesen wird. Um das
Datenwort korrekt zusammenzusetzen, wird es an die Stelle '0'
geschoben und maskiert, so dass der Rest von UCSRB wegfällt.

Zu 2.:
Im Prinzip ja. Wenn man sichergehen will, kann man
return ((unsigned int)((resh << 8) | resl));
schreiben.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ergänzung: Man könnte das Schieben um eins nach rechts wegoptimieren,
wenn man schreibt:

resh &= 0x02;
return ((resh << 7) | resl);

Wenn ich nix übersehen habe, müsste das so funktionieren. Allerdings
ist in der Originalvariante besser erkennbar, was da genau gemacht
wird.

Autor: Manfred S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, klingt logisch. Ich muß das 9. Bit ja eben an diese 9. Stelle des
16 Bit-Wertes bringen. Sonst würde es ja an 10. Stelle stehen.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu 2: Jeder korrekte C Compiler hat folgende Eigenschaften:
- "int" ist mindestens 16bit gross.
- jede Rechnung von Daten kleiner als "int" erfolgt als "int".
Wobei das natürlich vom Ergebnis her zu sehen ist, wenn das gleiche
rauskommt darf er auch kleiner rechnen. Hier aber nicht.

Der Return-Typ hingegen ist für die Rechnung nicht relevant: so ist
  return 1 << 8
gleich 256
  return 1 << 16
hingegen 0, auch wenn die Funktion als "long" deklariert ist.

Bei 8-Bit Microcontrollern sollte man freilich prüfen ober er
tatäschlich Standardkonform ist. Würd' mich nicht wirklich wundern,
wenn manche da Kompromisse eingehen.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@A.K.:
Afaik gilt das mit den Integer-Berechnungen aber nur für den
Präprozessor. Und die Operationen in dem return-Ausdruck im
Code-Beispiel aus dem Datenblatt können nicht zur Compiler-Laufzeit
(also vom Präprozessor) durchgeführt werden, da sie Variablen
enthalten, deren Werte zur Compile-Zeit nicht bekannt sind. Alle
anderen Operationen werden mit der für die verwendeten Größen
erforderlichen Datenbreite durchgeführt, eben auch in diesem Fall. Dein
Beispiel bezieht sich nur auf konstante Werte, die bereits zur
Compiler-Laufzeit bekannt sind. Und da trifft es tatsächlich zu, dass
diese Operationen standardmäßig in int durchgeführt werden. Will man
mehr, dann muss man dem Präprozessor das mitteilen. Und wenn die
Funktion einen Rückgabewert vom Typ long besitzt, dann müsste es z.B.
mit 'return (1 << 16)UL;' gehen.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Afaik gilt das mit den Integer-Berechnungen aber nur für den
Präprozessor."

Nö.

Ausserdem rechnet der Präprozessor ausschliesslich in seinen eigenen
Statements (#if 1+2 == 2), nie im C-Code (return 1+2).

Du meinst wahrscheinlich den Teil des Compilers, der konstante
Berechnungen selber ausführt und durch das Resultat ersetzt. Das ist
nicht der Präprozessor, sondern eine optionale Komponente des
Compilers. Und für den gilt was für alle Optimierungen gilt: er muss
genau so arbeiten als wenn es ihn nicht gäbe (im Rahmen des C-Standards
allerdings, es darf etwas anderes rauskommen, wenn das Ergebnis
undefiniert ist).

"'return (1 << 16)UL;'"

Was soll das denn für C sein?

Der Typ links einer Zuweisung oder des Resultats einer Funktion ändert
garantiert nie etwas an der Rechnung selber. Erst das Ergebnis der
Rechnung wird dann ggf. umgewandelt.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Alle anderen Operationen werden mit der für die verwendeten Größen
erforderlichen Datenbreite durchgeführt, eben auch in diesem Fall."

Nein

C89: "A char , a short int [...] may be used in an expression wherever
an int or unsigned int may be used.  If an int can represent all values
of the original type, the value is converted to an int ; otherwise it
is converted to an unsigned int ."

D.h.: Mit Operanden kleiner als "int" muss so gerechnet werden, als
würde die Rechnung mit "int" ausgeführt.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Richtig, aber bei für 8-Bit-µCs angepassten Compilern werden anscheinend
tatsächlich einige Änderungen gegenüber dem ANSI-Standard gemacht. Wie
das jetzt im Compiler intern aussieht, weiß ich nicht. Möglicherweise
wird da intern tatsächlich (nach ANSI-Standard) mit int gerechnet, aber
wenn 8 Bit reichen, dann kommt (in Assembler) auch eine 8-Bit-Operation
raus!

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Solange es im Ergebnis keinen Unterschied macht, darf der Compiler
beliebige Optimierungen durchführen. Das ist bekannt als "as-if
rule". Es ist egal, was der Compiler tatsächlich macht, solange es für
ein konformes Programm so aussieht, als hätte er es so gemacht, wie in
der C-Norm steht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.