Forum: Compiler & IDEs Was genau macht (uint16_t) ((uint32_t) F_CPU/BAUDRATE) ?


von Marc (Gast)


Lesenswert?

Guten Abend,


ich versuche gerade den Software-Uart-Code vom Roboternetz
( http://www.rn-wissen.de/index.php/Software-UART_mit_avr-gcc )
auf einem ATtiny25 zum laufen zu bekommen und verstehe die Funktion 
folgender Zeile nicht ganz:


OCR1A  = (uint16_t) ((uint32_t) F_CPU/BAUDRATE);

Ich kenne diese Typedefs bis jetzt nur aus den herkömmlichen 
Variablendeklarationen, aber das hier scheint etwas Anderes zu sein.

Meine Vermutung: "(uint32_t) F_CPU/BAUDRATE" teilt dem Compiler mit, 
dass er 32 Bit für den Wert reservieren soll, weiter links wird dann 
abgerundet.
Aber man merkt wohl, dass ich das Konzept noch nicht so ganz durchschaut 
habe.

Kann mir jemand etwas genauer erklären, was hier geschieht?

Vielen Dank schonmal!

Marc

von Naja (Gast)


Lesenswert?

>Ich kenne diese Typedefs...
Welche Typedefs. Ich sehe hier keines.

>... bis jetzt nur aus den herkömmlichen Variablendeklarationen
Typedefs werden in Typdeklarationen verwendet, nicht in 
Variablendeklarationen.
Der von Dir gezeigte Code aber ist eine Zuweisung; weder eine Variablen- 
noch eine Typdeklaration.

>..."(uint32_t) F_CPU/BAUDRATE" teilt dem Compiler mit, dass er 32 Bit für >den 
Wert reservieren...
Nein. Hier wird nichts "reserviert", sofern man unter reservieren das im 
Computerbereich übliche vorbehalten von RAM-Bereichen versteht.

Vielmehr wird gesagt, dass F_CPU ein uint32_t ist.


>...weiter links wird dann abgerundet.
Hier wird nirgends gerundet, weder links, noch rechts, noch oben, noch 
unten.

Aber das Ergebnis der Division von F_CPU durch BAUDRATE wird in ein 
uint16_t umgewandelt bevor es OCR1A zugewiesen wird.

von STK500-Besitzer (Gast)


Lesenswert?

>OCR1A  = (uint16_t) ((uint32_t) F_CPU/BAUDRATE);

>F_CPU/BAUDRATE
Berechnet eine Division.
Damit das Ergebnis auch noch sinnvoll ist, wird F_CPU auf uint32_t 
gecastet, also sein Zahlenbreich vergrößert.

Damit das Ergebnis auch wieder ins OCR1A-Register passt, wird zurück auf 
uint16_t gecastet. Sollte aber unnötig sein.
Sofern F_CPU und BAUDRATE keine Variablen sind, sollte man sich da 
Gecaste sparen können.

von Marc (Gast)


Lesenswert?

>... bis jetzt nur aus den herkömmlichen Variablendeklarationen
>Typedefs werden in Typdeklarationen verwendet, nicht in
>Variablendeklarationen.
>Der von Dir gezeigte Code aber ist eine Zuweisung; weder eine Variablen-
>noch eine Typdeklaration.

Typischer Fall von Verwechslung mangels soliden Grundwissens. Danke für 
die Richtigstellung - ich muss das alles dringend aufarbeiten.

>Damit das Ergebnis auch noch sinnvoll ist, wird F_CPU auf uint32_t
>gecastet, also sein Zahlenbreich vergrößert.

Ok, jetzt wird's langsam klar, vielen Dank! Und mit "casting" hab' ich 
das richtige Stichwort.

Eine Frage noch: Bezieht sich das casting allein auf F_CPU oder auf das 
Erebnis der Division?

von Karl H. (kbuchegg)


Lesenswert?

Marc schrieb:

> Ok, jetzt wird's langsam klar, vielen Dank! Und mit "casting" hab' ich
> das richtige Stichwort.
>
> Eine Frage noch: Bezieht sich das casting allein auf F_CPU oder auf das
> Erebnis der Division?

Operatoren Reihenfolge.(Stichwort für google: "operator precedence C")

http://www.difranco.net/cop2220/op-prec.htm

Casts stehen in der Hierarchie fast ganz oben, binden also sehr stark. 
Dementsprechend bezieht sich dieser Cast nur auf F_CPU


(Wobei diese Casts in diesem Ausdruck überflüssig sind. Der Ausdruck 
würde auch dann richtig berechnet, wenn keine Casts da wären. In diesem 
Fall sollte man sich an die Regel halten: Caste nur dann, wenn es 
wirklich unbedingt notwendig ist, ansonsten lass den Compiler seine 
Arbeit tun)

von Marc (Gast)


Lesenswert?

>http://www.difranco.net/cop2220/op-prec.htm
>
>Casts stehen in der Hierarchie fast ganz oben, binden also sehr stark.
>Dementsprechend bezieht sich dieser Cast auf F_CPU

Ok!

Vielen Dank und einen sonnigen Tag noch!

von ... .. (docean) Benutzerseite


Lesenswert?

die division wird aber auch in 32bit durchgeführt? oder nicht? eine 
Komponente hat ja 32Bit, erst das ergebins wird auch 16Bit 
zurechtgestutzt..

PS:
die uart Routinen von hier sind wesentlich besser...

von Karl H. (kbuchegg)


Lesenswert?

... ... schrieb:
> die division wird aber auch in 32bit durchgeführt? oder nicht? eine
> Komponente hat ja 32Bit, erst das ergebins wird auch 16Bit
> zurechtgestutzt..

Ja.

An dieser Stelle wird es Zeit den obligaten Hinweis zu geben:
Du brauchst vernünftige Literatur (zb einen Kernighan&Ritchie).
Da steht das alles (und noch viel, viel mehr) drinnen.

Ohne Unterlagen kann man eine Sprache wie C nicht vernünftig erlernen. 
Da gibt es viel zu viele kleine (und auch größere) Stolpersteine.

von JojoS (Gast)


Lesenswert?

#define F_CPU 1000000UL

die Typisierung 'UL' würde das casten auch überflüssig machen, könnte 
aber zu Fehlern führen wenn es dann fehlt. Wenn man verschiedene 
Quelltext mixt dürfte das explizite casten im Makro narrensicherer sein.

von Karl H. (kbuchegg)


Lesenswert?

JojoS schrieb:

> aber zu Fehlern führen wenn es dann fehlt. Wenn man verschiedene
> Quelltext mixt dürfte das explizite casten im Makro narrensicherer sein.

Grundsätzlich ja.
Aber nicht in diesem konkreten Fall. Hier gibt es keine Möglichkeit 
eines Überlaufs. Durch die Division wird das Ergebnis ja nur kleiner als 
die Ausgansgzahlen. Wenn die Ausgangszahlen int sind, dann wird auch das 
Ergebnis in int reinpassen. Ist eine der Ausgangszahlen zu groß für 
einen int, dann hebt der Compiler diese Zahl sowieso von sich aus von 
int eine Stufe höher (auf long). Das einzige was passieren könnte ist, 
dass man mit signed/unsigned ein Problem bekommt. Allerdings wird nach 
menschlichem Ermessen weder F_CPU noch BAUDRATE je negativ werden, wobei 
dann allerdings die Frage interessant wäre was denn das richtige 
Ergebnis sei. Bleibt also nur noch der Fall, dass der Compiler eine der 
beiden Zahlen aufgrund des Zahlenwertes als long ansieht, obowhl er das 
nicht müsste, weil es sich in einem unsigned int noch ausgehen würde. 
Der Fall ist aber müssig, da durch den Cast die ganze Berechnung auf 
jeden Fall (selbst bei kleinen Zahlen, ok, geschenkt F_CPU wird höchst 
wahrscheinlich auf AVR immer einen int sprengen) auf long angehoben 
wurde.

Laufzeitproblem ist das allerdings auch keines. Sind alles konstante 
Zahlenwerte, die der Compiler im Constant-Folding auswerten wird.

von STK500-Besitzer (Gast)


Lesenswert?

[OT]

>Vielen Dank und einen sonnigen Tag noch!

Bei uns regnet es...

[/OT]

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.