Hallo zusammen,
kann mir bitte mal jemand genau die folgende Anweisung bit für bit
erklären.
while (!(UCSR1A & (1<<UDRE1)))
Blick das mit den Opreatoren noch nicht so ganz... :-(
Ich blick das nicht ganz,
weil UCSR1A ist ja ein ganzes Register, also 8 bit.
bsp. 00100000 Wenn wir mal annehmen das die 1 UDRE1 ist
jetz verunde ich zusätzlich noch UDRE damit???
Was kommt dann in diesem bsp raus??
UDRE ist ein Makro, das in der Header-Datei definiert ist. Wenn UDRE das
Bit mit der Nummer 1 ist, dann steht in der Header-Datei
1
#define UDRE 1
Wenn man jetzt eine "1" (binär 00000001) um "UDRE" Stellen (also um eine
Stelle) nach links schiebt, dann erhält man 00000010. Und damit wird das
UCSR1A jetzt verknüpft. Der Rest steht in jedem C-Buch und -Tutorial.
EDIT:
Sorry, muss natürlich "UDRE1" heißen und nicht "UDRE"...
Es wird hier UCSR1A mit einer um den Wert von UDRE1 nach links
geschobenen "1" verundet.
UDRE1 wird irgendwo in einem Header als Zahl zwischen 0..7 definiert
sein. Also als das n-te Bit.
1 << 0 = 1
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
usw.
1 << UDRE1 = ?
Klar?
>kann mir bitte mal jemand genau die folgende Anweisung bit für bit>erklären.>while (!(UCSR1A & (1<<UDRE1)))>Blick das mit den Opreatoren noch nicht so ganz... :-(
entweder ein Wert von 0 oder 00100000. Durch die UND Maske kann es nur
diese 2 Zustände geben.
Normaleweise denkt man so
while ((UCSR1A & BitMaske) <> 0)
oder
while ((UCSR1A & BitMaske) == 0)
Nun gilt aber im C
1.) != statt <>
2.) kann man diese Schreibweise abkürzen durch Weglassen des
Vergleiches, und das ist sau doofe C Syntax
Also es wird dann so
while (UCSR1A & BitMaske) do
solange in UCSR1A and Bitmaske <> 0 ist mache das
while (!(UCSR1A & BitMaske)) do
solange NICHT in USCR1A and Bitmaske <> 0 ist mache das, also
solange in USCR1A ad Bitmaske == 0 ist mache das
Das ist eben C Syntax, und in moderneren Sprache kommt man wieder zurück
zu der expliziten Schreibweise. Also das was man denkt und liest
schreibt man auch explizit hin.
Bitte Leute, keine Diskussionen ob diese Syntax schlecht oder gut ist.
Ich weiß nur das meine Lehrlinge exakt damit immer Probleme hatten.
Gruß Hagen
Hagen Re wrote:
> Bitte Leute, keine Diskussionen ob diese Syntax schlecht oder gut ist.> Ich weiß nur das meine Lehrlinge exakt damit immer Probleme hatten.
Nee, nicht "gut" oder "schlecht", das ist tatsächlich Geschmackssache.
Aber Spock würde korrekterweise anmerken: "Faszinierend, die Syntax ist
logisch..."
Man muss einfach daran denken, dass in solchen Anweisungen
Wahrheitswerte ausgewertet werden, und ein Wahrheitswert kann nunmal nur
zwei Zustände annehmen, nämlich wahr oder falsch. Und man sollte
wenigstens versuchen, seinen Lehrlingen/Studenten/Wasauchimmer das
Denken in logischen Operationen nahezubringen. Klar, es gibt immer
Leute, die sich damit schwerer tun als andere, aber: Es ist
logisch...;-)
Ok dann hier nochmal ob ich es verstanden habe....
UCSR1A ist im Moment wenn ich in die while schleife eintrete so
00100000 wobei die 1 gerade UDRE1 ist.
So nun kommt meine Anweisung
while (!(UCSR1A & (1<<UDRE1)))
Die Schleife dürfte jetzt nicht durchlaufen werden, da
00100000
&
00100000
wieder
00100000
ergeben und das doch wahr ist???
Bin ich doof, ich blick das nicht HILFE....... ;-(
Lehrling.de
@Johannes, das bestreite ich nicht. Aber es soll Menschen geben die
Logik anderst sprechen und denken als das was die C Entwickler darunter
cerstanden als sie die C Syntax erschafften ;)
Da ich ebenfalls Logik anderst beigebracht bekommen habe, so wie man es
eben spricht, muß ich ebenfalls bei komplexeren C Abfrage immer noch im
Kopf umformulieren.
Gruß Hagen
Bastler wrote:
> Ok dann hier nochmal ob ich es verstanden habe....>> UCSR1A ist im Moment wenn ich in die while schleife eintrete so> 00100000 wobei die 1 gerade UDRE1 ist.>> So nun kommt meine Anweisung>> while (!(UCSR1A & (1<<UDRE1)))>> Die Schleife dürfte jetzt nicht durchlaufen werden, da>> 00100000> &> 00100000>> wieder>> 00100000> ergeben und das doch wahr ist???> Bin ich doof, ich blick das nicht HILFE....... ;-(> Lehrling.de
Wenn UDRE1 im Header als "5" definiert ist, dann hast Du das richtig
verstanden. Dann steht da im Klartext
1
while(!(UCSR1A&(1<<5)))
und "1 << 5" ist 00100000. Das mit dem UCSR1A bitweise verUNDet gibt
00100000 zurück (wobei es sogar egal ist, welchen Zustand die anderen
Bits im UCSR1A haben, denn 00100000 & XX1XXXXX gibt das selbe zurück).
00100000 wird jetzt mit dem logischen (!) Negierungsoperator "!"
verarbeitet. Dieser gibt genau dann eine 1 zurück, wenn der Operand 0
ist. Der ist aber nicht 0, sondern 00100000, was ungleich Null und
deshalb wahr ist. "!" gibt also eine 0 zurück. Dann steht da "while(0)".
Demnach wird nicht in die Schleife hineingesprungen.
@Bastler:
nochmal, in jeder Abfrage von IF und WHILE muß es zu einer Boolschen
Formel kommen. Also immer nur JA oder NEIN.
Jede der kompakten, vereinfacht geschriebenen Abfragen in C kann man
auch anders schreiben, nämlich so
while (X != 0) <- ungleich, <>
oder eben
while (X == 0)
Das lässt sich dann kürzer schreiben
while (X)
oder
while (!(X)) <- solange NICHT (X ungleich 0)
Viele Profi-C'ler verkürzen es auf diese Weise, einerseits weil man es
in der Mathematik der Boolschen Abfragen auch so schreibt, und
andererseit weil man so zeigen kann das man Profi "ist".
0 ist also immer bool'sch FALSCH, und alles was nicht 0 ist ist bool'sch
gesehen WAHR.
Gruß Hagen
2 Dinge:
* In C hat praktisch jeder Ausdruck einen Ergebnis-Wert.
Auch eine Zuweisung hat einen Wert, nämlich den Wert der
zugewiesen wurde. Das macht Dinge wie i = j = 5; möglich.
Auch ein Vergleich ist nichts anderes als ein Ausdruck, der
einen Wert liefert: i == 5 liefert 0 (FALSCH) oder 1 (WAHR)
je nachdem, ob i eben 5 ist oder nicht. Dies macht Dinge
wie j = ( i == 5 ); möglich, wo das Ergebnis eines Vergleiches
in einer Variablen abgespeichert wird. Ein Vergleich ist
auch nichts anderes als ein 'arithmetischer Ausdruck'
(im Englischen: eine Expression) so wie 2 + 3 auch.
Während 2 + 3 als Ergebnis 5 liefert, so liefert halt
der Ausdruck 5 == 7 eine 0 als Ergebnis.
* Wahrheitswerte sind nichts anderes als ganze Zahlen, wobei
0 die Bedeutung von FALSCH (FALSE) besitzt und alles was
nicht 0 ist, die Bedeutung WAHR (TRUE) besitzt.
In C gibt es keine expliziten boolschen Datentypen, man nimmt
einfach obige Konvention her und benutzt einen Ganzzahltyp.
Bolsche Werte sind also auch nur Zahlen und auch umgekehrt:
jede Zahl kann auch als boolscher Wert fungieren, wobei das
allerdings beim while gar nicht zum tragen kommt.
In C prüft eine while Schleife eiegentlich gar nicht, ob der
angegebene Ausdruck nun TRUE oder FALSE ergibt, sondern es wird
(in Ermangelung eines expliziten Boolschen Typen) geprüft, ob
der Ausdruck 0 oder eben nicht 0 (in Übereinstimmung mit der
Konvention für boolsche Auswertung, siehe Punkt 2 da oben) ist.
Das ist alles, was man wissen muss um zu verstehen, warum
while (!(UCSR1A & (1<<UDRE1)))
so ausgewertet wird, wie es wird. Entweder der Ausdruck
!(UCSR1A & (1<<UDRE1)) ergibt 0 oder ergibt nicht 0.
Hagen Re wrote:
> @Johannes, das bestreite ich nicht. Aber es soll Menschen geben die> Logik anderst sprechen und denken als das was die C Entwickler darunter> cerstanden als sie die C Syntax erschafften ;)>> Da ich ebenfalls Logik anderst beigebracht bekommen habe, so wie man es> eben spricht, muß ich ebenfalls bei komplexeren C Abfrage immer noch im> Kopf umformulieren.
Ich glaube nicht, daß das nur ein C-Problem ist.
Wer MCs programmieren will, muß einfach wissen, wie Binärzahlen
aufgebaut sind und wie bitweise Operatoren (~,&,|,^) funktionieren. Das
sind Grundlagen, da kommt keiner drumrum.
Es ist schon richtig, daß C auch logische Operatoren (!,&&,||) kennt,
damit kann man komplexe if,else-Ketten besser lesbar darstellen.
Aber warum zum Teufel gibts kein ^^ ?
Peter
Peter Dannegger wrote:
> Aber warum zum Teufel gibts kein ^^ ?
Das gibt's, das heißt aber !=.
1
if((a>b)^^(b<c)){
2
...
3
}
wäre dasselbe wie
1
if((a>b)!=(b<c)){
2
...
3
}
Wenn's dir besser gefällt, kannst du also
#define ^^ !=
schreiben. ;-) (Obiges trifft natürlich nur zu, wenn auf beiden
Seiten echte Wahrheitswerte stehen, also nur 0 und 1 zugelassen
sind.)
Jörg Wunsch wrote:
> Peter Dannegger wrote:>>> Aber warum zum Teufel gibts kein ^^ ?>> Das gibt's, das heißt aber !=.
Ich denke, Peter meinte mit ^^ das Potenzieren.
Ok vielen Dank an euch alle, ich denke jetzt hab ich es auch kappiert.
Bitte streitet euch jetzt nicht ob C gut oder schlecht ist. Könnte ich
schon so gut programmieren wie ihr, würde ich es für gut ansehen :-)
Danke nochmal
Gruß
Azubi
Jörg Wunsch wrote:
> Wenn's dir besser gefällt, kannst du also>> #define ^^ !=>> schreiben. ;-) (Obiges trifft natürlich nur zu, wenn auf beiden> Seiten echte Wahrheitswerte stehen, also nur 0 und 1 zugelassen> sind.)
Leider.
Man kann dann nicht schreiben:
Bastler wrote:
> Bitte streitet euch jetzt nicht ob C gut oder schlecht ist.
Hier geht es nicht um gut oder schlecht.
In einigen Bereichen von C hat man sich überlegt, ob man die
überhaupt braucht. So zb. bei boolschen Dingen
Und man ist zu den Schluss gekommen: Nein, eigentlich brauchen
wir die ja gar nicht. Mann muss nur seine Sichtweise der Dinge
etwas verändern.
Während in vielen anderen Sprachen die Syntax (vereinfacht)
so aussieht
if Ausdruck Vergleichsoperator Ausdruck then
hat man sich überlegt: Was wäre, wenn so ein Vergleichsoperator
auf einer Stufe mit den anderen arithmetischen Operatoren wie
+ - * / stehen würde, also einfach auch nur seine beiden
Operanden miteinander verknüpft und ein arithmetisches Ergebnis
liefern würde.
Und man ist zu dem Schluss gekommen, das das durchaus geht, dass
man also die Syntax von if, while vereinfachen kann zu
if Ausdruck then
Natürlich braucht man noch eine Konvention dafür, wie denn das
Ergebnis des Ausdruckes sein muss, damit der then Zweig genommen
wird, aber das ist eine Frage von Konventionen und man entschied
sich für die 0 - nicht 0 Regel.
Aber: Durch den Wegfall eines expliziten bool Typen konnte man
die Sprache einfacher halten ohne das es zu Einbussen gekommen
wäre, ganz im Gegenteil, man erhielt neue Freiheiten.
So kann man in C schreiben:
i = ( j == 5 ) * a + 3 * ( k < 8 );
Ein Vergleichsoperator liefert ja 1 wenn der Vergleich zutrifft
und 0 wenn er nicht zutrifft. Dementsprechen ist das Ergebnis
von ( j == 5 ) * a, genau dann a wenn j gleich 5 ist (weil ja
1 * a wieder a ergibt, während 0 * a immer 0 ist).
In Langform ist obiges also
if( j == 5 )
i = a;
else
i = 0;
if( k < 8 )
i = i + 3;
ok. zugegeben. Die kompremierte Syntax ist für den Anfang etwas
schwer zu lesen. Wenn man sich aber mal dran gewöhnt hat, dann
kommt sie einem relativ natürlich vor. Und klarerweise benutzt
man sowas eher selten (da es meist relativ sinnlos ist). Aber
man kann zb das hier machen:
foo( a, b, i == 5 );
anstelle von
if( i == 5)
foo( a, b, 1 );
else
foo( a, b, 0 );
und das sieht man schon etwas häufiger.
Das führte aber zwangsläufig dazu das sich die Syntaxgrenzen zwischen
den einzelnen Sprachelementen verwischten. Also Zuweisung und Boolsche
Abfragen in einem einzigsten Konstrukt. Und das wäre mein
Hauptkritikpunkt an C. Andere Sprache reduzierten absichtlich diese
Möglichkeiten der sehr flexiblen Schreibweisen für den gleichen
Sachverhalt, die restriktiven Sprachen. Solche erlernt man viel leichter
und intuitiver als C.
Wichtig ist aber letzendlich nur eines: Hat man sich in C rein-"gequält"
wird es immer mehr Spaß machen. Ein Vorteil ist eben auch das wenn man C
kann wird man die einfacheren restriktiven Sprachen leichter erlernen.
Ich kann eben bestätigen das gerade bei diesen Syntaxkonstrukten die
Lehrlinge die meisten Probleme haben und Fehler machen. Bevor das nicht
sitzt braucht man die Pointerarithmetiken garnicht anfangen.
Gruß Hagen
Nun ist C auch nicht dazu gedacht, als Lehr- oder Unterrichtssprache
genutzt zu werden, sondern primär als Werkzeug. Und das hat halt auch
Eigenschaften, die es dem, der es kennt, sehr einfach machen, sie zu
nutzen, die aber dem, der es nicht kennt, nur sehr schwer zu vermitteln
sind.
C ist nicht Pädagogik. Programmieren ist auch nicht Pädagogik.
Pädagogik im Sinne einiger mehr oder weniger brauchbarer Lehr- und
Unterrichtssprachen kommt aus dem Hause Wirth*.
*) Niklaus Wirth, Pascal, Modula(2), Oberon ...
Hagen Re wrote:
> Wichtig ist aber letzendlich nur eines: Hat man sich in C rein-"gequält"> wird es immer mehr Spaß machen.
Das sicherlich.
Wenn ich jemanden in die Grundzüge von C einführe, fang ich auch nicht
mit diesen Kurzschreibweisen an, sondern achte darauf, dass er
die Langformen benutzt
if( i == 0 )
if( ptr == NULL )
Irgendwann studiert er dann auch mal andere Programme und dann kann
man ihn langsam an die "Wahrheit" heranführen und schrittweise in
die Geheimnisse der Kurzschreibweisen einführen. Die ersten davon
werden sicherlich ++, --, +=, -= usw. sein.
>> Ich kann eben bestätigen das gerade bei diesen Syntaxkonstrukten die> Lehrlinge die meisten Probleme haben und Fehler machen.
Das glaub ich gerne.
> Bevor das nicht> sitzt braucht man die Pointerarithmetiken garnicht anfangen.
:-) Die nächste große Hürde.
Danach kommt noch der Übergang von 1-Stern Programmierung zu
2-Stern Programmierung, der erstaunlicherweise (obwohl völlig
logisch) auch immer wieder zu Problemen führt
Karl heinz Buchegger wrote:
> Danach kommt noch der Übergang von 1-Stern Programmierung zu> 2-Stern Programmierung, der erstaunlicherweise (obwohl völlig> logisch) auch immer wieder zu Problemen führt
Wenn sie dann endlich denken, sie hätten C schon verstanden, kann
man sie noch mit dem ternären operator (?:) überraschen.
Anschließend kommt als Prüfungsaufgabe das Schreiben einer
Funktion, die einen Zeiger auf den Typ ihrer selbst übernimmt
und einen ebensolchen zurück gibt, und zwar ohne Benutzung
von typedef. :-))
Schließlich und endlich blieben noch geschachtelte obskure
Präprozessorkonstrukte übrig, in denen es von # und ## nur so
wimmelt. ;-)