![]() |
|
|||||||
| Newsgroup de.comp.os.unix.programming Programmierung unter Unix. |
![]() |
|
|
Themen-Optionen | Ansicht |
|
#1
|
|||
|
|||
|
Ich bin gerade dabei zur Übung ein Kernelmodul zu schreiben. Variablen Definition: short errzaehl = 0; Im Programm (in einer Funktion): errzaehl = ++errzaehl & 0x1FFF; Ergibt beim Kompilieren für diese Zeile die Meldung: Warnung: Operation auf >errzaehl< könnte undefiniert sein. Ändere ich das ganze hingegen ab: ++errzaehl; errzaehl = errzaehl & 0x1FFF; gibt es keine Warnung. Da ist der gcc zufrieden. Warum? gcc 3.4.6 (Ubuntu 3.4.6-8ubuntu2) unter Linux. Danke und Gruß Martin |
|
|
||||
|
||||
|
|
|
#2
|
|||
|
|||
|
Martin Freiberg schrieb:
> Ich bin gerade dabei zur Übung ein Kernelmodul zu schreiben. > > Variablen Definition: > short errzaehl = 0; > > Im Programm (in einer Funktion): > > errzaehl = ++errzaehl & 0x1FFF; > > Ergibt beim Kompilieren für diese Zeile die Meldung: > > Warnung: Operation auf >errzaehl< könnte undefiniert sein. > > Ändere ich das ganze hingegen ab: > > ++errzaehl; > errzaehl = errzaehl & 0x1FFF; > > gibt es keine Warnung. Da ist der gcc zufrieden. Warum? > > gcc 3.4.6 (Ubuntu 3.4.6-8ubuntu2) unter Linux. Auf das Objekt 'errzaehl' wir im ersten Beispiel zwischen zwei Sequenzpunkten mehr als einmal schreibend zugegriffen. Wie sich ein Programm (der Wert in dem Objekt) dann zu verhalten hat, ist nicht definiert. cc |
|
#3
|
|||
|
|||
|
Claudio Carobolante schrieb:
> Martin Freiberg schrieb: >> errzaehl = ++errzaehl & 0x1FFF; >> Warnung: Operation auf >errzaehl< könnte undefiniert sein. >> ++errzaehl; >> errzaehl = errzaehl & 0x1FFF; >> gibt es keine Warnung. Da ist der gcc zufrieden. Warum? > Auf das Objekt 'errzaehl' wir im ersten Beispiel zwischen zwei > Sequenzpunkten mehr als einmal schreibend zugegriffen. Wie sich ein > Programm (der Wert in dem Objekt) dann zu verhalten hat, ist nicht > definiert. Sorry, aber das kapiere ich jetzt nicht. Ist Ersteres nicht nur die Kurzform für das zweite Beispiel? Ich lese es so das so das im ersten Beispiel zuerst der Wert dieser Variable inkrementiert wird, dann die binäre Und-Verknüpfung erfolgt und zuletzt das Ergebnis wieder in der Variable landet. Die Reihenfolge ist doch fest vorgegeben, oder etwa nicht? Gruß Martin |
|
#4
|
|||
|
|||
|
Martin Freiberg schrieb:
>>> errzaehl = ++errzaehl & 0x1FFF; >>> Warnung: Operation auf >errzaehl< könnte undefiniert sein. > >>> ++errzaehl; >>> errzaehl = errzaehl & 0x1FFF; > Sorry, aber das kapiere ich jetzt nicht. > > Ist Ersteres nicht nur die Kurzform für das zweite Beispiel? Nein. ++errzaehl ist (vom Ergebnis her) die Abkürzung für (errzaehl = errzaehl + 1). Also lautet Dein erstes Beispiel errzaehl = (errzaehl = errzaehl + 1) & 0x1FFF; Nur - welche der Beiden Zuordnungen gilt nun? Das ist eben undefiniert. Was Du vermutlich willst, ist errzaehl = (errzaehl + 1) & 0x1FFF; > Ich lese es so das so das im ersten Beispiel zuerst der Wert dieser > Variable inkrementiert wird, dann die binäre Und-Verknüpfung erfolgt und > zuletzt das Ergebnis wieder in der Variable landet. Eben. Die Variable wird zweimal beschrieben - ohne Sequenzpunkt dazwischen. Dies macht die Reihenfolge der Auswertung undefiniert. Ebenso könnte folgendes passieren: errzaehl wird inkrementiert, ver&et und dann an errzaehl zugewiesen, und danach wird der inkrementierte, aber unver&ete Wert in die Variable geschrieben. Und außerdem - warum zweimal zuweisen? Eine Zuweisung am Ende sollte doch ausreichen... Thomas |
|
#5
|
|||
|
|||
|
Thomas Rachel schrieb:
> Martin Freiberg schrieb: >>>> errzaehl = ++errzaehl & 0x1FFF; >>>> Warnung: Operation auf >errzaehl< könnte undefiniert sein. >>>> ++errzaehl; >>>> errzaehl = errzaehl & 0x1FFF; >> Ist Ersteres nicht nur die Kurzform für das zweite Beispiel? > Nein. > ++errzaehl ist (vom Ergebnis her) die Abkürzung für > (errzaehl = errzaehl + 1). > Also lautet Dein erstes Beispiel > errzaehl = (errzaehl = errzaehl + 1) & 0x1FFF; Oha, und ich dachte das ++errzaehl eindeutig ist und klar ein vorhergehendes increment der Variablen bedeutet. Zumal doch die Reihenfolge gilt, das Klammern zuerst abgearbeitet werden. > errzaehl = (errzaehl = errzaehl + 1) & 0x1FFF; müsste dann nach Klammerregel doch zu errzaehl = errzaehl + 1; errzaehl = errzaehl & 0x1FFF; werden. Wenn man die Klammern weg lässt bzw. die öffnende verschiebt errzaehl = errzaehl = (errzaehl + 1) & 0x1FFF; dann währe die Sache vollends klar. > Was Du vermutlich willst, ist > > errzaehl = (errzaehl + 1) & 0x1FFF; Lässt sich das korrekt zu errzaehl = (++errzaehl) & 0x1FFF; abkürzen, oder sollte man diese Abkürzungen vermeiden und lieber ++errzaehl; errzaehl &= 0x1FFF; schreiben? Danke & Gruß Martin |
|
#6
|
|||
|
|||
|
Hallo,
Martin Freiberg <lyki_*web.de> wrote: > Thomas Rachel schrieb: >> Martin Freiberg schrieb: >>>>> errzaehl = ++errzaehl & 0x1FFF; >>>>> Warnung: Operation auf >errzaehl< könnte undefiniert sein. >>>>> ++errzaehl; >>>>> errzaehl = errzaehl & 0x1FFF; >>> Ist Ersteres nicht nur die Kurzform für das zweite Beispiel? >> Nein. >> ++errzaehl ist (vom Ergebnis her) die Abkürzung für >> (errzaehl = errzaehl + 1). >> Also lautet Dein erstes Beispiel >> errzaehl = (errzaehl = errzaehl + 1) & 0x1FFF; > Oha, und ich dachte das ++errzaehl eindeutig ist und klar ein > vorhergehendes increment der Variablen bedeutet. Das ist auch so. Allerdings kannst du dich erst ab dem naechsten "Sequenzpunkt" darauf verlassen, dass die Variable um eins erhoeht wurde. Die Erhoehung des Variablenwertes kann *irgendwann* vor dem nachsten Sequenzpunkt erfolgen, also sowohl vor als auch nach der Wertzuweisung (und wenn der um eins erhoehte urspruengliche Wert von erzaehl erst *nach* der Zuweisung wieder in der Variable erzaehl gespeichert wird, ueberschreibt das den neu zugewiesenen Wert von erzaehl ...). Der Ausdruck erzaehl++ ist durchaus klar und eindeutig, aber er veraendert den Wert von erzaehl. Und zwischen zwei Seuqenz- punkten darf der Wert eienr Variablen nur *einmal* veraendert werden, sonst ist das Ergebnis undefiniert. Ein Sequnezpunkt waere z.B. das Semikolon am Ende eines Statements (es gibt noch einige Moeglich- keiten mehr). Der Ausdruck "erzaehl++" hat einen Wert, und zwar den vorherigen Wert von erzahl um 1 erhoeht. Aber auch wenn der Wert des Ausdrucks in deinem Beispiel sicher vor der Zuweisung berechnet werden muss, heisst das nicht, dass die "Nebenwirkung" des Ausdrucks (Aenderung des Wertes der Variablen erzahl) auch schon vor der Zu- weisung statfinden muss: der Standard garantiert nur, dass diese "Nebenwirkung" irgendwann vor dem naechsten Sequenzpunkt vollendet ist. > Zumal doch die Reihenfolge gilt, das Klammern zuerst abgearbeitet werden. > > errzaehl = (errzaehl = errzaehl + 1) & 0x1FFF; Das spielt fuer die Berechnung der Werte der Ausdruecke eine Rolle, nicht aber fuer die Reihenfolge der Wertaenderungn der Variablen. Ja, das ist ein Untrerschied. Die Reihenfolge der "Wertaenderungen der Variablen" kannst du nicht beeinflussen, solange da kein Sequenzpunkt dazwischen liegt (bei einem Sequenzpunkt muessen alle Wirkungen eines Ausdrucks vor diesem Sequenzpunkt vollstaendig abgearbeitet sein). > müsste dann nach Klammerregel doch zu > > errzaehl = errzaehl + 1; > errzaehl = errzaehl & 0x1FFF; > > werden. Nein, siehe oben. Diese Fassung hat nur dshalb gegenueber der dort oben stehenden nicht das selbe Problem, weil du durch die Aufteilung auf 2 Statements einen Sequenzpunkt (das Semikolon nach der ersten Zeile) zwischen den beiden Ausdruecken die den Wert von erzaehl veraendern eingefuegt hast. > Wenn man die Klammern weg lässt bzw. die öffnende verschiebt > > errzaehl = errzaehl = (errzaehl + 1) & 0x1FFF; > > dann währe die Sache vollends klar. Die Zuweisung ist kein Sequenzpunkt, deswegen waere der Ausdruck noch immer "undefiniert" (denn du hast in der gesamten Zeile keinen Sequenz- punkt). >> Was Du vermutlich willst, ist >> >> errzaehl = (errzaehl + 1) & 0x1FFF; > > Lässt sich das korrekt zu > > errzaehl = (++errzaehl) & 0x1FFF; > > abkürzen, oder sollte man diese Abkürzungen vermeiden und lieber Damit kuerzt du doch gar nichts ab. Abgesehen von den (nicht zwingend erforderlichen) Leerzeichen sind doch beide Zeilen exakt gleich lang. Aber selbst wenn deine Fassung nicht "undefiniert" waere, haette sie nicht die geringsten Vorteile. > ++errzaehl; > errzaehl &= 0x1FFF; > > schreiben? Das koennte man, aber warum sollte man das tun? Ist diese Version fuer dich klarer und schneller erkennbar als >> errzaehl = (errzaehl + 1) & 0x1FFF; ? Wohl eher nicht, also warum so etwas schreiben? Um den Ruf von C als "kryptische Sprache" zu festigen? Tschuess, Juergen Ilse (juergen*usenet-verwaltung.de) -- Ein Domainname (auch wenn er Teil einer Mailadresse ist) ist nur ein Name, nicht mehr und nicht weniger ... |
|
#7
|
|||
|
|||
|
Juergen Ilse <juergen*usenet-verwaltung.de> writes:
> Martin Freiberg <lyki_*web.de> wrote: [...] >> ++errzaehl; >> errzaehl &= 0x1FFF; >> >> schreiben? > > Das koennte man, aber warum sollte man das tun? Ist diese Version fuer dich > klarer und schneller erkennbar als Fuer mich ist sie das zum Beispiel: Es werden nacheinander zwei Manipulationen des Wertes von errzaehl vorgenommen, zum einen wird der Wert inkrementiert, zum anderen der inkrementierte Wert modulo 8192 'heruntergebrochen'. Logisch haben diese beiden Operationen nichts miteinander zu tun, genausogut koennte in der ersten Zeile in Dekrement erfolgen oder in der zweiten eine Beschraenkung auf einen anderen Zahlenbereich. >>> errzaehl = (errzaehl + 1) & 0x1FFF; > > ? Wohl eher nicht, also warum so etwas schreiben? Um den Ruf von C als > "kryptische Sprache" zu festigen? Dafuer wuerde ich errzaehl = errzaehl + 1 & 0x1fff vorschlagen (ja, die Prioritaeten sind so) :->. Es ist mir allerdings nicht ganz ersichtlich, warum der zusammengesetzte Ausdruck anstelle der zwei separaten Operationen aus sich heraus irgendwie 'verstaendlicher' sein sollte: Er dehnt sich in die Breite anstatt in die Laenge und ich wuerde ihn einen truegerischerweise mathematischer aussehenden nennen (truegerisch wegen des &). |
|
#8
|
|||
|
|||
|
Juergen Ilse schrieb:
> Martin Freiberg <lyki_*web.de> wrote: Hallo, > Das ist auch so. Allerdings kannst du dich erst ab dem naechsten > "Sequenzpunkt" darauf verlassen, dass die Variable um eins erhoeht > wurde. Sprich, der Compiler zerlegt das ganze und sortiert das unter Umständen um? Also sollte ich davon ausgehen das wenn ich eine korrekte Reihenfolge haben will, am besten für jeden Befehl eine eigene Zeile verwende. > erzaehl ...). Der Ausdruck erzaehl++ ist durchaus klar und eindeutig, > aber er veraendert den Wert von erzaehl. Und zwischen zwei Seuqenz- > punkten darf der Wert eienr Variablen nur *einmal* veraendert werden, > sonst ist das Ergebnis undefiniert. Ein Sequnezpunkt waere z.B. das Was mich aber noch mehr verwirrt. ![]() Bei errzaehl = (errzaehl +1) & 0x1FFF; müsste doch das gleiche Problem auftreten. Denn der Ausdruck innerhalb der Klammer macht doch auch nichts anderes den Wert der Variable um eins zu erhöhen. Oder wird liegt hier drin wiederum ein Sequenzpunkt? Irgend wie bin ich da jetzt ein wenig Begriffsstutzig. ![]() >> errzaehl = (++errzaehl) & 0x1FFF; >> abkürzen, oder sollte man diese Abkürzungen vermeiden und lieber > > Damit kuerzt du doch gar nichts ab. Abgesehen von den (nicht zwingend > erforderlichen) Leerzeichen sind doch beide Zeilen exakt gleich lang. Ich habe gelesen das man durch die Leerzeichen Fehler vermeiden kann. >> ++errzaehl; >> errzaehl &= 0x1FFF; > > Das koennte man, aber warum sollte man das tun? Ist diese Version fuer dich > klarer und schneller erkennbar als > >>> errzaehl = (errzaehl + 1) & 0x1FFF; Ja. Zumal mir der unterschied zwischen dieser Version und der mit ++errzaehl noch nicht völlig einleuchtet. Zudem habe ich gelesen das man ++Variable vorziehen sollte, da hier oft der effizientere Code erstellt wird. Oder erkennen heutige Compiler das und codieren eine Addition um ein zu einem Increment-Befehl um? > ? Wohl eher nicht, also warum so etwas schreiben? Um den Ruf von C als > "kryptische Sprache" zu festigen? Es liegt wohl mehr am Schreibstil ob etwas Kryptisch ist oder nicht. :-) Gruß Martin |
|
#9
|
|||
|
|||
|
Hallo,
Martin Freiberg <lyki_*web.de> wrote: >> erzaehl ...). Der Ausdruck erzaehl++ ist durchaus klar und eindeutig, >> aber er veraendert den Wert von erzaehl. Und zwischen zwei Seuqenz- >> punkten darf der Wert eienr Variablen nur *einmal* veraendert werden, >> sonst ist das Ergebnis undefiniert. Ein Sequnezpunkt waere z.B. das > Was mich aber noch mehr verwirrt. ![]() > Bei > errzaehl = (errzaehl +1) & 0x1FFF; > müsste doch das gleiche Problem auftreten. Nein. > Denn der Ausdruck innerhalb der Klammer macht doch auch nichts anderes > den Wert der Variable um eins zu erhöhen. Nein. Der Ausdruck ergibt den um ein erhoehten Inhalt der Variablen, *aber* der Variablenwert wird dabei *nicht* veraendert (und genau ist der Grund, weshalb in *deiner* Fassung der Compiler eine Warnung schmeisst: da wird namlich der Variablenwert unnoetigerweise veraendert). > Oder wird liegt hier drin wiederum ein Sequenzpunkt? Nein, aber der Wert von erzahl wird durch den Ausdruck (errzaehl +1) *nicht* veraendert. >>> errzaehl = (++errzaehl) & 0x1FFF; >>> abkürzen, oder sollte man diese Abkürzungen vermeiden und lieber >> Damit kuerzt du doch gar nichts ab. Abgesehen von den (nicht zwingend >> erforderlichen) Leerzeichen sind doch beide Zeilen exakt gleich lang. > Ich habe gelesen das man durch die Leerzeichen Fehler vermeiden kann. Das ist zwar richtig, aber wenn du die Laenge zweier Ausdruecke vergleichen willst, erscheint es mir unpraktisch, dabei unnoetige Lerrzeichen mitzu- zaehlen ... >>> ++errzaehl; >>> errzaehl &= 0x1FFF; >> Das koennte man, aber warum sollte man das tun? Ist diese Version fuer dich >> klarer und schneller erkennbar als >>>> errzaehl = (errzaehl + 1) & 0x1FFF; > Ja. OK, das ist GEschmacksache (und kommt vielleicht auch auf den Kontext an). > Zumal mir der unterschied zwischen dieser Version und der mit > ++errzaehl noch nicht völlig einleuchtet. > Zudem habe ich gelesen das man ++Variable vorziehen sollte, da hier oft > der effizientere Code erstellt wird. Wenn man den Variablenwert dadurch auch aendern will: vielleicht, wobei das bei vielen modernen Compilern aber keinen wesentlichen Unterschied ausmacht (der Optimizer wuerde i.d.R. bei sehr vielen Compilern aus den folgenden Zeilen: ++erzaehl; erzaehl++; erzaehl+=1; erzaehl=erzaehl+1; jeweils identischen Code erzeugen. > Oder erkennen heutige Compiler das und codieren eine Addition um ein zu > einem Increment-Befehl um? Sehr viele moderne Compiler ja. Tschuess, Juergen Ilse (juergen*usenet-verwaltung.de) -- Ein Domainname (auch wenn er Teil einer Mailadresse ist) ist nur ein Name, nicht mehr und nicht weniger ... |
|
|
|
|