buffer++; // Der Pointer zeigt anschließend auf den nächsten Eintrag
*data++; // Es wird zunätzlich nachgeschaut, welchen Wert der Inhalt
hat, auf den der Zeiger zeigte.
Zu Pointern:
http://et-tutorials.de/3368/pointer-in-c/
Daniel_s schrieb:
ok, nun lassen wir mal das auslesen in die data variable weg, dann
bleibt nur ein
buffer++;
Und warum hat dieses buffer++ die selbe funktion wie ein *data++ ?
liefert als Ergebnis den Wert von buffer (also eine Adresse), und als
Nebeneffekt wird buffer anschließend inkrementiert. Oftmals wird auch
nur der Nebeneffekt (also die Inkrementierung) dieses Ausdrucks genutzt.
Dann schreibt man den Ausdruck einfach isoliert in eine ANweisung.
1
*data++
liefert wegen des *-Operators als Ergebnis das Zeichen, auf das data
zeigt und hat als Nebeneffekt ebenfalls die Inkrementierung. Wenn auch
hier wie im ersten Beispiel nur der Nebeneffekt genutzt würde, wäre die
Dereferenzierung unnütz, weil das Ergebnis dieser Operation ja gleich
anschließend weggeschschmissen wird. *data++ hätte dann also den
gleichen Effekt wie data++ (Ausnahme: data ist als volatile
deklariert). In deinem putsUART wird der Wert von *data++ aber
tatsächlich verwendet, nämlich um abzufragen, ob das String-Ende
(NUL-Zeichn) erreicht ist.
data++
und
*data++
wären nun klar.
wie sieht es aus mit:
&data++
Das dürfte doch das selbe sein wie data++
es liefert die addresse von data und inkrementiert
Und wie verhält sich das anders bei volatile?
David,
das Problem, das Du da hast, ist wahrscheinlich folgendes:
Du hast eine globale Variable data, die als unsigned char definiert ist.
In der Funktion gibt es eine weitere Variable, die auch data heißt, die
als
char *data
definiert ist, also ein Zeiger auf ein char.
Also, nicht durcheinander werfen.
Und besser: verschiedende Namen verwenden.
Garden schrieb:> Sorry, die erste Variable ist nicht global, sondern in main() definiert.> Das Fazit ist aber das Gleiche: Besser unterschiedliche Namen verwenden.
Variablen in Funktionen benenne ich nach deren Inhalt, unabhängig davon,
ob in einer anderen Funktion (dazu zählt auch main) eine Variable gleich
heisst. Auch wenn in einer anderen Sourcedatei eine globale Veriable mit
dem selben Namen existiert.
Folgendes sollte man jedoch zu Gunsten der Übersichtlichkeit vermeiden:
be stucki schrieb:> Variablen in Funktionen benenne ich nach deren Inhalt, unabhängig davon,> ob in einer anderen Funktion (dazu zählt auch main) eine Variable gleich> heisst.
Du bist wahrscheinlich auch kein Programmier-Anfänger, wie der
Frage-Steller.
Bei größeren Projekten weiß man ja auch gar nicht, wie andere ihre
lokalen Variablen nennen. Ist auch egal.
Wenn man aber mit dem Programmieren anfängt, ist es hilfreich Variablen
unterschiedlich zu benennen, um nicht alles durcheinader zu werfen.
David Mueller schrieb:> Und wie verhält sich das anders bei volatile?
volatile ist hier eher Nebenschauplatz. Yalu hat es nur angeführt, damit
ihm nicht irgendwer hinten nach in die Parade fährt und 5 Postings lang
darüber rummosert, dass er unpräzise war.
Aber um das anzusprechen. Bei
1
voidfoo()
2
{
3
*data++;
4
}
kann und wird der Compiler drauf kommen, dass die Derferenzierung
effektiv ja nichts bewirkt, weil ja mit dem so ermittelten Wert gar
nichts gemacht wird. Der Compiler kann also die Derferenzierung effektiv
einfach weglassen, weil sich (aus seiner Sicht) am Programm ja nichts
ändert.
Nun, das muss aber nicht stimmen. WEnn data ein Pointer auf eine
Hardware ist, die auf den reinen Vorgang des Auslesens hin etwas macht
(keine Ahnung: Sirene heult, Blinklicht geht an, etc.) dann gibt es
einen Unterschied, denn im Falle das der Compiler optimiert, findet ja
das eigentliche Auslesen nie statt. Und mit volatile kann man das
verhindern. volatile ist für den Compiler quasi die Aufforderung "Keine
Optimierungen erlaubt"
> Warum wird buffer++ ohne ein * geschrieben und *data++ mit einem *> Ich verstehs einfach nicht,
Deine Frage ist fast so sinnvoll, wie die Frage:
Warum schreibt ein Prorgrammierer einmal die Berechnung des Umfangs
eines Kreises so
1
tmp=2*Radius;
2
Umfang=tmp*PI;
und einmal so
1
Umfang=2*Radius*PI;
In deinen beiden Funktionen könnte jeweils die gleiche Syntax benutzen,
wenn man wollte. Schaun wir uns mal an, was da rauskommen würde.
Fall 1: das *data++ im puts soll beibehalten werden. Wie müsste gets
aussehen, wenn es die gleiche Syntax benutzen will.
So
1
voidgetsUSART(char*buffer,unsignedcharlen)
2
{
3
chari;// Length counter
4
5
for(i=0;i<len;i++)// Only retrieve len characters
6
{
7
while(!DataRdyUSART());// Wait for data to be received
8
9
*buffer++=getcUART();// Get a character from the USART
10
// and save in the string
11
}
12
}
warum der Programmierer das nicht gemacht hat? Keine Ahnung. Vielleicht
hat ihn die Courage verlassen das ++ auch auf der linken Seite einer
Zuweisung einzusetzen oder es war ihm nicht wichtig genug, weil der
Optimizer seinen Originalcode sowieso auf diese Version zusammenkürzen
würde. Vielleicht wollte er auch einfach nur eine Hilfsvariable haben,
damit er mit dem Debugger rankommt.
Fall 2: Die Derferenzierung wird vom Inkrement getrennt, so wie das um
gets gemacht ist. Wie muss dann das puts aussehen?
So
1
2
voidputsUSART(char*data)
3
{
4
charc;
5
6
do
7
{// Transmit a byte
8
while(BusyUSART());
9
10
c=*data;
11
data++;
12
13
putcUART(c);
14
15
}while(c);
16
}
Man sieht auch: Die Einführung einer Hilfsvariablen c bringt dem Code
eigentlich kaum Klarheit, wenn man sein C lesen kann. Sie zieht den Code
nur unnötig in die Länge.
D.h. Ob man die eine Schreibweise benutzt oder die andere ist eigentlich
... in diesen Fällen .... relativ egal. Das eine lässt sich in das
andere umformen und welche Schreibweise man benutzt ist weitgehend
Geschmackssache.
vielen Dank für die Ausführliche Erklärung.
Karl Heinz Buchegger schrieb:> void foo()> {> *data++;> }
Er würde bei einer Optimierung aber nur die Derferenzierung entfernen
oder?
Das inkrementieren wird bei behalten?
David Mueller schrieb:> vielen Dank für die Ausführliche Erklärung.>> Karl Heinz Buchegger schrieb:>> void foo()>> {>> *data++;>> }>>> Er würde bei einer Optimierung aber nur die Derferenzierung entfernen> oder?> Das inkrementieren wird bei behalten?
Kann man so nicht sagen.
ein vollständiges Programm
1
unsignedchari=5;
2
staticunsignedchar*data=&i;
3
4
staticvoidfoo()
5
{
6
*data++;
7
}
8
9
intmain()
10
{
11
foo();
12
}
Optimierungen laufen nach der 'AS-IF' Regel.
D.h. der Optimizer darf alles machen, solange der nach aussen
beobachtbare Effekt derselbe bleibt.
Im obigen Programm kann der Compiler (nach dem inlinen) auch das
Inkrementieren wegoptimieren, weil data sonst nirgends benutzt wird, es
also keinerlei beobachtbare Effekte gibt ob es stattfindet oder nicht.