Forum: Mikrocontroller und Digitale Elektronik Ring-Puffer Indexierung


von S. Leven (Gast)


Lesenswert?

Guten Tag,
könnte mir jemand einen Tip geben, warum zwischen den folgenden beiden
Code-Versionen für eine Ring-Puffer-Implementierung (dsPic30F6014,
C30)
ein Unterschied sein könnte:

//defines und deklarierte Variablen
..
#define rvmask 15
unsigned int rxbuf[rvmask+1];
unsigned char rxbufp=0;
unsigend int rxr;
..

//Code-Version 1:
..
rxbufp = (rxbufp++)&rvmask;
rxr = rxbuf[rxbufp];
..

//Code-Version 2:
..
rxbufp++;
rxbufp = rxbufp&rvmask;
rxr = rxbuf[rxbufp];
..

Die zweite Code-Version funktioniert einwandfrei, während bei der
ersten die Maskierung von rxbufp überhaupt nicht funktioniert und der
Ring-Puffer-Indexierung fehlschlägt. rxbufp wird nicht wieder auf Null
gebracht beim überschreiten von rvmask (erst beim char-overflow von
255->0 wird der Wert automatisch wieder Null).

Wieso das? Hat jemand eine Idee. Vielen Dank.
S. Leven

von tastendrücker (Gast)


Lesenswert?

In Version 2 wird rxbufp zuerst incrementiert und dann mit rvmask
verknüpft. Um das gleiche zu erzielen müsste Version 1 IMO so
aussehen:

rxbufp = (++rxbufp)&rvmask;
rxr = rxbuf[rxbufp];

von vexti (Gast)


Lesenswert?

ist das nicht so, daß rxbuf selbst schon eine Adresse (pointer) ist?
Bischen komisch finde ich...

g. Vex

von Karl heinz B. (kbucheg)


Lesenswert?

> ist das nicht so, daß rxbuf selbst schon eine Adresse (pointer) ist?

Wie kommst du da drauf?

unsigned int rxbuf[rvmask+1];

rxbuf ist eindeutig ein Array.
Ein Array ist kein Pointer!
Ein Array ist kein Pointer!
Ein Array ist kein Pointer!

von Peter D. (peda)


Lesenswert?

Unter rxbufp würde ich einen Pointer (Adresse) vermuten, ist also
irreführend.

Einen Index sollte man rxbufi oder besser rxbuf_idx nennen.


Peter

von vexti (Gast)


Lesenswert?

@Karl ähm .. ich hab da was anderes gelesen ein Array bzw. der
Bezeichner ist in erster Linie eine Adresse eines Speicherberiches und
jetzt sag mir mal was dann ein Pointer ist..

ich schreib das mal, was ich bei mir da stehen hab

Pointer und Arrays
Zwischen beiden besteht ein sehr enger Zusammenhang, der soweit geht,
dass der Name eines Arrays selbst ohne Array-Index[i] schon ein Pointer
vom Typ der Arrayelemenete ist.... (Quelle: C für Microcontroller B.
Mann)

von vexti (Gast)


Lesenswert?

Übrigens steht da auch ein Beispiel zu den Puffer:

int DataArray[8];
int *pInt;
pInt = DataArray;     //diese Zuweisung
pInt = &DataArray[0]; //oder diese sind indentisch

pInt += 1; //Zeigt auf das nächste Arrayelement identisch mit pInt++
pInt -= 1; //zeigt auf das vorherrige Element identsich mit pInt--

von tastendrücker (Gast)


Lesenswert?

pInt ist in deinem Beispiel der Pointer:

pInt ist ein Bezeichner für eine Speicheradresse, in dieser
Speicheradresse steht die Adresse eines Elements von DataArray.

von vexti (Gast)


Lesenswert?

jau war mir schon klar wie das geht .. bin nur bei Source oben nicht
ganz schlau draus geworden und wie es schon Peter sagte mit den Pointer
Bezeichnern da drin kann man das schon etwas missverstehen, was nun ein
Pointer und was die eigentliche Speicherstelle ist

Vex

von Karl heinz B. (kbucheg)


Lesenswert?

> Karl ähm .. ich hab da was anderes gelesen ein Array bzw. der
> Bezeichner ist in erster Linie eine Adresse eines Speicherberiches
> und jetzt sag mir mal was dann ein Pointer ist..

Wenn das dort tatsächlich so gestanden hat, dann verbrenne
sofort die Quelle (das Buch) und grab die Asche 3 Meter
tief ein.

Das ist eine der größten Falschinformationen über C.

Ein Array ist kein Pointer!

Ein Array ist ein Speicherbereich in dem Werte gespeichert
werden. Die Sammlung all dieser Werte ist unter dem Namen
des Arrays bekannt.

Ein Pointer seinerseits ist eine ganz normale Variable, die
eine Speicheradresse beinhaltet.

Teil der Konfusion ist sicherlich die übliche Vorgehensweise
den Terminus 'Pointer' für 2 verschiedene Dinge zu verwenden:
* Für eine Variable, die eine Speicher-Adresse enthält
* Für die Speicher-Adresse selbst.

Wie ist es wirklich:
Wird der Name eines Arrays alleine verwendet (also ohne
einen Indizierungsausdruck), so degeneriert der Name des
Arrays zur ersten Speicheradresse des ersten Array-Elements.
(Da fängts schon an: Ich habe bewusst 'erste Speicheradresse
geschrieben. Übliche Ausdrucksweise ist: ... degeneriert zu einem
Pointer auf das erste Array-Element).
Wichtig: Das ganze ist immer noch ein Array und kein Pointer!
Nur weil etwas wie ein Pointer benutzt wird, heist es nicht
das das ein Pointer ist!

Wenn du also hast:

  int Tmp[5];

dann degeneriert der Ausdruck 'Tmp' alleine in den meisten
Fällen (eine Ausnahme wäre zb. sizeof) zu einem Pointer auf
das erste Element von Tmp. So zb in

    foo( Tmp );

Hier degeneriert Tmp zu einem Pointer auf Tmp[0]. Man könnte
auch salopp sagen, dass 'Tmp' synonym ist zu '&Tmp[0]'

Ein interessanter Punkt in C ist die Art und Weise wie
Array-Zugriffe überhaupt definiert sind. In C ist Array-
Indizierung eine ganz banale Sache. Es ist definiert, dass
der Compiler einen Ausdruck der Form:
      a[b]
sofort in die Form
      *(a+b)
umformen muss.

d.h. hier kommt wieder der Name des Arrays alleine vor (a) und
daher degeneriet dieser Ausdruck sofort zu ersten Speicheradresse
des Arrays. b ist der Index und wie immer bei Pointer-Arithmetik
wird dbei Addition eines Integer-Typen zu einem Pointer, der
Integer-Typ zuerst mit dem sizeof des Pointer-Quelltyps multipliziert.

Obiges ist daher equivalent zu:

   *( ((unsigned char*)a) + b * sizeof( *a ) )

Diese Transformation macht der Compiler intern, wenn er auf einen
Ausdruck
    a[b]
stoesst.

Interessant, aber völlig logisch, ist daher, dass man auch
schreiben kann

  int a[5];
  int b;

  b[a]

Der Compiler muss das akzeptieren, da ja dieser Ausdruck
equivalent zu

  *(b + a)

ist und Addition kummutativ ist. b + a ist dasselbe wie a + b
Und ob ich jetzt zu einem Pointer einen Integer hinzuzähle oder
zu einem Integer einen Pointer spielt keine Rolle.

Ein Fall an dem es ganz besonders ins Auge geht, dass ein Array
eben kein Pointer ist, ist folgender:

In einer C-Einheit vereinbart man eine globale Variable

  int Array[5];

und in einer anderen C-Einheit versucht man Zugang zu dieser
globalen Variable zuerhalten:

   extern int* Array;

Das kann so nicht gut gehen. Denn wie gesagt: Ein Array ist
kein Pointer. Im ersten Fall bezeichnet der Name Array einen
Speicherbereich an dem die tatsächlichen int-Werte zu finden sind.
Im zweiten Fall aber wird deklariert, dass Array der Name eines
Speicherbereiches ist, in dem die tatsächliche Speicheradresse
zu finden ist, an dem die int abeleget sind.

In graphischer Form (und irgendwelche Werte für die int angenommen)

  Array
  +----+----+----+----+----+
  |  0 | 20 | 30 | 40 | 10 |
  +----+----+----+----+----+

versus

  Array
  +------+                +----+----+----+----+----+
  |  o------------------->|  0 | 20 | 30 | 40 | 10 |
  +------+                +----+----+----+----+----+

man sieht recht deutlich, dass das 2 vollkommen verschiedene
Dinge sind, auch wenn beide Varianten (und dass ist das perverse
daran) mit vollkommen identischer Syntax beim Zugriff benutzt
werden.

Die richtige Schreibweise wäre im 2-ten Fall
  extern int Array[];
und das ist (wie bereits gezeigt) was völlig anderes als
  extern int* Array;

Klarer?

von tastendrücker (Gast)


Lesenswert?

... wie ich sehe, ist Karl Heinz schon etwas über "Hallo Welt" hinaus
;-). Sauber erklärt!

von vexti (Gast)


Lesenswert?

Ja Danke echt gut erklärt Karl!

aber ich wollte auch nie sagen, daß ein Array ein Pointer ist sondern
andeuten, daß ein Array Bezeichner  genau wie ein Pointer lediglich
eine Adresse (nat. wenn der Pointer eine zugewiesen bekommen hat)
darstellt .. und mehr nicht.
Genau aus dem Grund - weil ein Array kein Pointer ist, würde ich z.B.
einer Funktions nicht ein Array , sondern den Pointer auf dieses
übergeben .. klar oder?

Gruss Vex

von vexti (Gast)


Lesenswert?

da Fällt mir noch was ein..

ich hatte mal Probs mit diesen Code:

char myarray[8];

int tuwas(int *p_array);

 und wenn ich jetzt die Funktion aufrufe mit tuwas(&myarray) .. rate
mal was dann passiert?

von Karl heinz B. (kbucheg)


Lesenswert?

Klar

Dann habe ich Deine Aussage

> ist das nicht so, daß rxbuf selbst schon eine Adresse (pointer) ist?

falsch interpretiert.
Sorry dafür.

Es ist nur so, dass diese Thematik eine der grossen
Stolpersteine für alle C-Einsteiger ist. Daher reagiere
ich ein klein wenig allergisch, wenn im selbsen Satz die
Wörter 'Array', 'Pointer' und 'ist' vorkommen.

von A.K. (Gast)


Lesenswert?

"rxbufp = (rxbufp++)&rvmask;"
"rxbufp = (++rxbufp)&rvmask;"

Ist beides undefiniert, weil hier effektiv zwei Zuweisungen an rxbufp
enthalten sind ("=" und "++"), und mangels sequence point nicht
definiert ist, welche zuerst erfolgt. "=" ist kein sequence point.

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.