Forum: Compiler & IDEs Ansi C Frage..


von Chris... (Gast)


Lesenswert?

ich arbeite gerade die Arikel durch..1a die dinger..:)

aber ich habe eine frage auf bestimmte code zeile:

outp ((1 << RXEN) | (1 << TXEN), UCR);

ich weiss was die zeile macht aber ich versteh die einzelnen zeichen 
net... ich kenne << nur als bit shiftoperand und nicht als zeichen um 
ein bit zu setzen. und dann noch der | das ist für mich eine veroderung 
und macht in meinen augen keinen sinn. wäre super wenn mir einer von 
euch helfen könnte.

von mikki merten (Gast)


Lesenswert?

Dient zum setzen der Bits RXEN (UART Receiver enable) und TXEN (UART 
Receiver enable) an der ensprechenden Position im UCR (UART Control 
Register).

von Schmittchen (Gast)


Lesenswert?

> ich kenne << nur als bit shiftoperand
So wird das hier auch gebraucht.

> und dann noch der | das ist für mich eine veroderung
auch das stimmt so.

(1 << RXEN) schiebt die "1" um genau so viele Positionen nach links, wie 
der Wert in der Konstanten RXEN besagt. RXEN wurde die Zahl 4 
zugewiesen, damit wird aus einer "1" durch 4x schieben das Bitmuster 
00010000.
(1 << TXEN) ergibt 00001000. Die bieden Klammern verODERt wird zu 
00011000 und das wird dem Register UCR zugewiesen.

Schmittchen.

von Chris... (Gast)


Lesenswert?

das ist mir schon klar...ich hatte ja schon erwähnt das ich weiss was 
der befehl macht..nur ich weiss nicht wieso...

von Chris... (Gast)


Lesenswert?

hey super danke schmittchen...:D

von Popei (Gast)


Lesenswert?

Soviel zum thema gut lesebarer code ... ;-)

von nobody0 (Gast)


Lesenswert?

Ist doch ganz einfach zu lesen; sorgar die Klammerung sieht gut aus.
Das ist schön kurz, knapp und präzise.

von Chris (Gast)


Lesenswert?

yo..haste recht NOB...wenn man das verstanden hat ist das echt super...

von Christian Schifferle (Gast)


Lesenswert?

Ich könnte sowas natürlich auch mit 2 Hilfsvariablen und 5 Zeilen Code 
lösen, aber so viel Platz haben wir ja eigentlich gar nicht in unseren 
Controllern oder ;-)

BYTE maske1, maske2;
maske1 = 1 << RXEN;
maske2 = 1 << TXEN;
outp (maske1 | maske2, UCR);

Das Verständnis der Bitschiebebefehle und der Bitoperatoren gehört zum 
Basiswissen bei der C-Programmierung. Kann bei Bedarf alles im Teil 1 
des Tutorials nachgelesen werden.

Gruss
Christian

von Schmittchen (Gast)


Lesenswert?

> aber so viel Platz haben wir ja eigentlich gar nicht in unseren Controllern oder 
;-)

Ich sehe zwar den Smiley, trotzdem noch eine Ergänzung:
Die Schreibweise im 1.Posting belegt nur 1 Zeile im Editor, und nur eine 
Zeile im Maschinencode (out UCR, 0x18). Die 0x18 kann der Compiler 
(Präprozessor) schon erzeugen und muß nicht jedesmal zur Laufzeit 
errechnet werden.
In Christians Beispiel werden im Normalfall 4 Zeilen Maschinencode 
daraus. (2x Zuweisung, 1x OR, 1x OUT ; das shift löst der Compiler 
selbst auf).

Theoretische Überlegung:
Eigentlich könnte der Compiler auch Chrisitans Code in eine einzige 
Maschinencodezeile optimieren (out UCR, 0x18). Wenn zuvor sichergestellt 
ist, dass kein Interrupt dazwischen kommen kann, dann kann ich mir keine 
Programmkonstellation/zustand vorstellen, bei dem die Zeilen nicht durch 
out UCR, 0x18 ersetzt werden können!? Ich vermute aber, daß das dem 
Compiler bzw. den Compilerprogrammierern zu weit geht und es nicht so 
gemacht wird.

Schmittchen.

von Peter D. (peda)


Lesenswert?

@Schmittchen

Wenn Du Variablen verwendest, denkt der Compiler, daß Du Dir dabei was 
gedacht hast und optimiert sie nicht so einfach weg.
Sonst hättest Du ja #define genommen:


#define maske1 (1 << RXEN)
#define maske2 (1 << TXEN)
outp (maske1 | maske2, UCR);

So sinds dann wieder nur 2 Zeilen Assembler.

Peter

von Schmittchen (Gast)


Lesenswert?

> Wenn Du Variablen verwendest, denkt der Compiler, daß Du Dir dabei was gedacht 
hast
Ja klar, aber in dem speziellen Falle könnte er sie wegoptimieren, 
ohne die Funktion des Programmes zu verändern. (Ich geb ja zu, daß das 
ein sehr spezieller, konstruierter und weithergeholter Fall ist - 
genauso wie zu fordern, daß der Compiler aus deinem Code nur 1 Zeile 
machen soll.).


Schmittchen.

von Peter D. (peda)


Lesenswert?

@Schmittchen

"genauso wie zu fordern, daß der Compiler aus deinem Code nur 1 Zeile 
machen soll"

Ist doch unmöglich !
Um einen Wert in ein I/O-Register zu schreiben, brauchst Du mindestens 2 
Instruktionen:

ldi r16, 1<<RXEN^1<<TXEN
out UCR, r16


Direkt irgendwas im I/O zu machen geht nur beim 8051 (MOV, INC, DEC, 
DJNZ, ANL, ORL, XRL). Deshalb ist ja Code auf dem 8051 typischer Weise 
kleiner als auf dem AVR.


Peter

von Jonas Diemer (Gast)


Lesenswert?

der 8051 braucht ja aber auch 12mal soviele takte pro instruktion! :-)

von Schmittchen (Gast)


Lesenswert?

> Um einen Wert in ein I/O-Register zu schreiben, brauchst Du mindestens 2 
Instruktionen:
Stimmt! Für mich war das eine Instruktion, aber das kann der AVR ja 
leider nicht. Also stimmen meine Angaben oben auch nicht ganz.

Aber manchmal geht der Compiler ja auch zu weit... siehe Beispiele leere 
Warteschleife wegoptimieren (kann der Compiler ja nicht wissen) oder die 
volatile-Geschichte. In beiden Fällen muß man den Compiler explizit 
darauf "hinweisen".

Schmittchen.

von nobody0 (Gast)


Lesenswert?

> Aber manchmal geht der Compiler ja auch zu weit... siehe Beispiele leere 
Warteschleife wegoptimieren ...

Nee, das ist schon richtig, das unnützer Code wegoptimiert wird. Wenn 
das nicht gemacht würde, müsste man auch die Kommentare übernehen und 
nicht wegoptimieren!

Wenn Optimierung eingeschaltet ist, sollte eine leere Warteschleife 
immer wegoptimiert werden.

von Peter D. (peda)


Lesenswert?

Eine Warteschleife sollte niemals wegoptimiert werden, wenn der 
Compilerbauer mitgedacht hat.

Optimieren heißt doch nur sinnlosen Code zu entfernen aber eine 
Warteschleife ist doch eindeutig als sinnvoll zum Warten zu erkennen.

Wenn ein Compilerbauer also leere Schleifen wegoptimiert, hat er 
entweder keine praktische Programmiererfahrung oder er will den Nutzer 
ärgern.


@Jonas,

stimmt, die meisten 8051 laufen mit 1 MIPS (Quarz = 12MHz), weil das 
oftmals mehr als ausreichend ist. Aber für die 
Geschwindigkeitsfetischisten gibts auch 8051-er mit max 50 MIPS (bzw. 
100 MIPS als Samples), z.B von Cygnal.


Peter

von Christian Schifferle (Gast)


Lesenswert?

Diese Aussage kann ich so nicht stehen lassen.
Bedenkt bitte, dass der C-Compiler nicht ausschliesslich zum 
Programmieren von Mikrocontrollern entwickelt wurde und bei "normalen" 
Anwendungen soll schliesslich nicht gewartet, sondern möglichst zügig 
gearbeitet werden.
Insofern ist es aus Sicht des Compilers völlig in Ordnung, für ihn 
sinnlose (weil leere) Loops wegzuoptimieren.

Christian

von nobody0 (Gast)


Lesenswert?

>Eine Warteschleife sollte niemals wegoptimiert
>werden, wenn der Compilerbauer mitgedacht hat.

Ja, aber eine leere Schleife ist doch keine Warteschleife, ausser man 
sagt das dem Compiler explizit. Ansonsten könnte der Compiler ja nichts 
optimieren!

Beim MSPGCC sieht eine ganz einfache Warteschleife deshalb so aus:

 for(i=0;i<1234;i++) _asm_ __volatile__("; loop");

Das die Schleife ohne volatile wegoptimiert ist doch auch das was man 
haben möchte, denn nach einigen tausend Zeilen Code kann ein Mensch 
wegoptimierbaren Code kaum erkennen, so das der Compiler das übernehmen 
muss.

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.