Hallo,
ich möchte an ein Schieberegister Daten ausgeben. Jetzt habe ich mir mal
den Artikel "Portexpander" im Roboternetz Wissen Bereich durchgelesen.
Funktioniert auch alles, bloß kann ich mir als C Einsteiger den Code
nicht ganz erklären. Das ärgert mich gerade sehr.
Hier mal der Code:
/* SERiell nach PArallel (serpa) via Software */
#include "serpa.h"
/* Array fuer die Daten */
unsigned char serpa[SERPA_SIZE];
void serpa_init ()
{
/* Verwendete Ports auf OUT */
MAKE_OUT (PORT_SER);
MAKE_OUT (PORT_SCK);
MAKE_OUT (PORT_RCK);
/* SCR und RCK auf definierten Level HIGH */
SET (PORT_SCK);
SET (PORT_RCK);
}
void serpa_out ()
{
unsigned char anz = SERPA_SIZE;
unsigned char* serp = serpa+SERPA_SIZE; //???
// do...while pro Byte einmal -> wird bestimmt durch Array Größe
do
{
unsigned char bits; //Anzahl Bits
unsigned char data = *--serp; // ??? wohl ein Pointer
/* 8 Bits pro Byte rausschieben */
// for schleife pro Bit einmal durchlaufen (8 mal)
for (bits = 8; bits > 0; bits--)
{
CLR (PORT_SER); //SER Port auf Masse
if (data & 0x80) //???
{
SET (PORT_SER); //SER Port auf 1
}
data <<= 1; //???
/* Strobe an SCK schiebt Daten im Gaensemarsch */
/* um 1 Position weiter durch alle Schieberegister */
CLR (PORT_SCK); //Takt Port auf Masse
SET (PORT_SCK); //Takt auf 1
}
}
while (--anz > 0);
/* Strobe an RCK bringt die Daten von den Schieberegistern in die
Latches, also übernehmen wenn alle Arrays geschoben wurden*/
CLR (PORT_RCK);
SET (PORT_RCK);
}
Ich habe den Code mal soweit kommentiert wie ich klar komme. Mit * wird
wohl ein sog. Pointer benutzt? Ich habe mal im Netz und im GCC Tutorial
nach Antworten gesucht, leider ohne Erfolg :-(
Ich wäre euch dankbar wenn wir den Code so auseinander nehmen können das
auch ich es verstehe.
DANKE
@ technikus (Gast)
>Funktioniert auch alles, bloß kann ich mir als C Einsteiger den Code>nicht ganz erklären.
Dann nimm doch ASM.
AVR-Tutorial: Schieberegister> unsigned char* serp = serpa+SERPA_SIZE; //???
Ein Pointer auf einen char wird initialisiert.
unsigned char data = *--serp; // ??? wohl ein Pointer
Verringere den Pointer um 1 und lies den Inhalt.
Pointerdereferenzierung.
> if (data & 0x80) //???
UND-Verknüfung von data und 0x80, prüft das MSB (Bit 7)
data <<= 1; //???
data wird um eins nach links geschoben
>wohl ein sog. Pointer benutzt? Ich habe mal im Netz und im GCC Tutorial>nach Antworten gesucht, leider ohne Erfolg :-(
Logisch. C-grundlagen werden hier nur minimal erklärt. Dazu solltest du
dier ein grundlagenbuch zulegen.
MfG
Falk
technikus wrote:
> unsigned char* serp = serpa+SERPA_SIZE; //???
fängt von hinten an, also letztes Byte zuerst
> unsigned char data = *--serp; // ??? wohl ein Pointer
holt sich das Byte und zählt den Pointer runter
> if (data & 0x80) //???
Testet Bit 7
> data <<= 1; //???
Schiebt nach links, d.h. Bit 0 -> Bit 1, .... Bit 6 -> Bit 7
Peter
Hallo,
danke für die Info!
@Peter: Fangen wir von hinten an:
>> data <<= 1; //???>Schiebt nach links, d.h. Bit 0 -> Bit 1, .... Bit 6 -> Bit 7
Werden dann Nullen nachgeschoben? Z.B. erst 10101010, dann <<1, jetzt
01010100 ?
>> if (data & 0x80) //???>Testet Bit 7
Das ist mir jetzt klar ( wohl auch schon vorher ;-) )
>> unsigned char data = *--serp; // ??? wohl ein Pointer>holt sich das Byte und zählt den Pointer runter
Ich habe mir mal Grundlagen über C angelesen. Irgendwie kriege ich das
mit den Pointern nicht hin und stelle mich zu doof an.
>> unsigned char* serp = serpa+SERPA_SIZE; //???>fängt von hinten an, also letztes Byte zuerst
Deswegen verstehe ich das hier auch nicht so recht. serpa ist doch ein
Array? Was ergibt denn dann serpa+SERPA_SIZE?
Müsste es nicht heißen: unsigned char* serp = serpa[SERPA_SIZE]; ??
Danke für die Hilfe! Vielleicht verstehe ich das ja auch mal. Es wäre
schön wenn mir jemand Beispiele mit Werten nennt.
Gruß
technikus
technikus wrote:
>>> unsigned char* serp = serpa+SERPA_SIZE; //???>>>fängt von hinten an, also letztes Byte zuerst>> Deswegen verstehe ich das hier auch nicht so recht. serpa ist doch ein> Array? Was ergibt denn dann serpa+SERPA_SIZE?> Müsste es nicht heißen: unsigned char* serp = serpa[SERPA_SIZE]; ??
Nein, "serpa" ist kein Array, sondern es ist der Name eines Arrays.
Und in C repräsentiert der Name eines Arrays die Adresse des ersten
Elements. Der Pointer wird deklariert und gleichzeitig initialisiert,
und zwar mit der Adresse des letzten Array-Elements von "serpa[]"
(also der Adresse des ersten Elements plus der Länge des Arrays).
Ist aber verständlich, dass das etwas verwirrend ist. Für EInsteiger
übersichtlicher könnte man schreiben
1
unsignedchar*serp;
2
serp=serpa+SERPA_SIZE;
Dann ist auch glasklar, was da wirklich gemacht wird. Ich denke, Dich
hat das Sternchen irritiert, das ja normalerweise als
Dereferenzierungsoperator dem Ziel des Pointers einen Wert zuweist.
Bei der Deklaration sieht das aber anders aus.
Deine Variante würde übrigens dazu führen, dass der Pointer mit dem
Inhalt der Speicherzelle nach dem letzten Element des Arrays
initialisiert würde. "serpa[SERPA_SIZE]" existiert schließlich nicht.
Das letzte Array-Element ist "serpa[SERPA_SIZE-1]".
Johannes M. wrote:
> Deine Variante würde übrigens dazu führen, dass der Pointer mit dem> Inhalt der Speicherzelle nach dem letzten Element des Arrays> initialisiert würde. "serpa[SERPA_SIZE]" existiert schließlich nicht.> Das letzte Array-Element ist "serpa[SERPA_SIZE-1]".
Ne, ist schon richtig so, das *--serp macht ein pre-decrement, bevor es
den Inhalt der Adresse liest und alles ist wieder in Butter.
Hinter ein Array zu zeigen ist erlaubt, davor zu zeigen ist undefiniert.
Peter
Peter Dannegger wrote:
> Hinter ein Array zu zeigen ist erlaubt, davor zu zeigen ist undefiniert.
Hab ja auch nichts anderes behauptet. Der von Dir zitierte Text bezog
sich auf die Zeile
> Müsste es nicht heißen: unsigned char* serp = serpa[SERPA_SIZE]; ??
in technikus' Post von 9:56. Und da kommt auf jeden Fall nicht das raus,
was eigentlich beabsichtigt ist...
Ich hatte mich allerdings tatsächlich oben verschrieben. Es hätte
natürlich heißen müssen "Der Pointer wird deklariert und gleichzeitig
initialisiert,
und zwar mit der Adresse des letzten Array-Elements von "serpa[]"
plus 1 (also der Adresse des ersten Elements plus der Länge des
Arrays)."
Da kommt dann hinterher das Pre-Decrement ins Spiel.
Und dass man hinter ein Array zeigen darf, heißt ja noch lange nicht,
dass da was Sinnvolles steht (ich denke, man kann sagen, dass da
meistens nichts Sinnvolles steht...).
Langsam verstehe ich.
Also so?:
do
{
unsigned char bits; //Anzahl Bits
unsigned char data = *--serp; // gucke auf serpa
[2], [1], [0] (Je Schleifendurchlauf)
/* 8 Bits pro Byte rausschieben */
// for schleife pro Bit einmal durchlaufen (8 mal)
for (bits = 8; bits > 0; bits--)
{
CLR (PORT_SER); //SER Port auf Masse
if (data & 0x80) // Abfragen ob Bit 7 ==
"1"
{
SET (PORT_SER); //SER Port auf 1
}
data <<= 1; //Bits nach links
schieben
/* Strobe an SCK schiebt Daten im Gaensemarsch */
/* um 1 Position weiter durch alle Schieberegister */
CLR (PORT_SCK); //Takt Port auf Masse
SET (PORT_SCK); //Takt auf 1
}
}
while (--anz > 0);
Hätte man dann nicht auch eine Zählschleife aufbauen können? Etwa so:
for (i=2,i>0,i--)
{
unsigned char bits; //Anzahl Bits
unsigned char data = serp[i]; // gucke auf serpa
[2], [1], [0] (Je Schleifendurchlauf)
/* 8 Bits pro Byte rausschieben */
// for schleife pro Bit einmal durchlaufen (8 mal)
for (bits = 8; bits > 0; bits--)
{
CLR (PORT_SER); //SER Port auf Masse
if (data & 0x80) // Abfragen ob Bit 7 ==
"1"
{
SET (PORT_SER); //SER Port auf 1
}
data <<= 1; //Bits nach links
schieben
/* Strobe an SCK schiebt Daten im Gaensemarsch */
/* um 1 Position weiter durch alle Schieberegister */
CLR (PORT_SCK); //Takt Port auf Masse
SET (PORT_SCK); //Takt auf 1
}
}
Also für 3 Bytes.
Habe ich jetzt richtig verstanden? Danke für Eure Mühe und Geduld.
technikus wrote:
> Langsam verstehe ich.
das hier:
unsigned char* serp = serpa+SERPA_SIZE;
ist identisch zu
unsigned char* serp = &serpa[SERPA_SIZE];
Aber das sollte mitlerweile schon klar geworden sein.
Graphisch passiert folgendes
serpa
+---+---+---+---+---+---+--- ... ---+---+---+
| | | | | | | | | |
+---+---+---+---+---+---+--- ... ---+---+---+
^
|
serp |
+-------+ |
| o------------------------------------------+
+-------+
serp wird also so eingerichtet, dass er auf das Element unmittelbar
hinter dem Array zeigt.
*--serp; macht dann folgendes:
-- wie immer wird die rechts davon stehende Variable
dekrementiert.
Da es sich aber um einen Pre-Dekrement handelt, ist das
Ergebnis das Ausdrucks, der Wert der Variablen nach dem
dekrementieren.
i = 5;
j = i--; i wird um 1 verringert, wird also zu 4.
j kriegt aber den Wert 5 (i vor dem Verringern)
i = 5;
j = --i; i wird um 1 verringert, wird also zu 4.
j kriegt den Wert von i nach dem Verringern.
j wird also ebenfalls zu 4
Bezogen auf den Pointer:
Wenn der Pointer um 1 verringert wird, zeigt er danach auf das
unmittelbar vorhergehende Element
serpa
+---+---+---+---+---+---+--- ... ---+---+---+
| | | | | | | | | |
+---+---+---+---+---+---+--- ... ---+---+---+
^
|
serp |
+-------+ |
| o--------------------------------------+
+-------+
Nachdem serp um 1 verringert wurde, holt dann der Dereferenzier-
operator, der * in *--serp, den Wert von der Speicheradresse,
die serp nach dem Dekrementieren hat. Also von dort, wo der Pfeil
jetzt hinzeigt.
> Hätte man dann nicht auch eine Zählschleife aufbauen können? Etwa so:
Ja. Hätte man machen können.
unsigned char Array[SIZE];
for( i = 0; i < SIZE; ++i )
j = Array[i];
ist gleichwertig zu
unsigned char Array[SIZE];
unsigned char* Address = Array; // oder &Array[0], was das gleiche
// ausdrückt.
for( i = 0; i < SIZE; ++i, Address++ )
j = *Address;
Dasselbe natürlich auch dann, wenn man das Array nicht in
der Reihenfolge 0, 1, 2, 3 sondern genau anders rum abarbeiten
möchte.
Ein guter Compiler formt die erste Form selbsttätig in die
zweite Form um.
@ Karl heinz Buchegger (kbuchegg) (Moderator)
> -- wie immer wird die rechts davon stehende Variable>dekrementiert.> Da es sich aber um einen Pre-Dekrement handelt, ist das> Ergebnis das Ausdrucks, der Wert der Variablen nach dem> dekrementieren.
Sollte man das nicht besser so erklären?
1
i=5;
2
j=i--;// j kriegt Wert von i (5)
3
// i wird *danach* um 1 verringert, wird also zu 4
4
// weil der Operator -- NACH der Variable steht
5
6
i=5;
7
j=--i;// i wird zuerst um 1 verringert, wird also zu 4
8
// weil der Operator ++ VOR der Variable steht
9
// j kriegt den Wert von i nach dem Verringern, also 4
Falk Brunner wrote:
> Sollte man das nicht besser so erklären?>
1
>i=5;
2
>j=i--;// j kriegt Wert von i (5)
3
>// i wird *danach* um 1 verringert, wird also zu 4
4
>// weil der Operator -- NACH der Variable steht
5
>
Konzeptionell kann man das schon so erklären. Das einzige
Problem dabei ist, dass dir der C-Standard keine Garantie für die
zeitliche Abfolge der Ereignisse gibt. Ob die Zuweisung tatsächlich
vor dem Dekrement erfolgt oder erst danach (natürlich mit dem
alten Wert), ist vom Standard her offen gelassen. Dort heist es einfach
nur: Beim nächsten Sequence Point ist alles erledigt (Sequ.Point ist
in diesem Fall der ;)
Solange du also die Formulierung nicht so wählst, dass der Leser
hier eine zeitliche Reihung zu erkennen glaubt, bin ich durchaus
mit der Formulierung einverstanden.
PS: Mir ist schon klar, dass du im Wesentlichen einen Zusammenhang
zwischen der Position des ++ und der Art der Dekrementierung
bauen willst. Kein Einwand dagegen. Nur wie gesagt: Hüte dich davor,
hier Begriffe wie 'davor' oder 'danach' zu benutzen.
@ Karl heinz Buchegger (kbuchegg) (Moderator)
>zeitliche Abfolge der Ereignisse gibt. Ob die Zuweisung tatsächlich>vor dem Dekrement erfolgt oder erst danach (natürlich mit dem>alten Wert), ist vom Standard her offen gelassen. Dort heist es einfach
Ohje, der C-"Standard". Aber gibt es Compiler, die das verdrehen? Ich
meine da kann man doch nix optimieren? Jaja, es gibt da dievers
C-Monsterkonstrukte, aber davon reden wir glaube ich nicht.
MfG
Falk
Falk Brunner wrote:
> Aber gibt es Compiler, die das verdrehen?
Ich kann mich dunkel an einen Bericht in comp.lang.c++
erinnern, in dem ein Poster einen Compiler hatte der
sowas machte. Ich weiss aber keine Details mehr dazu auswendig.
Ist schon ein paar Jährchen her und das war irgendein esoterischer
Compiler.
@ ARM-Fan (Gast)
>>der Visual C++ 6.0 Compiler inkrementiert i.>KEIL C51 auch.
Das ist einer der vielen Punkte, die mir bei C auf den Zeiger gehen.
Solche Operationen, die wieder in einer Operation Parameter verändern.
Das ist nichts als ne Stolperfalle ohne jeden realen praktischen
Nutzen. Viva Pascal!
MfG
Falk
ARM-Fan wrote:
>>der Visual C++ 6.0 Compiler inkrementiert i.>> KEIL C51 auch.
IMHO muss das auch so sein.
Der Compiler muss die längste Kette bilden.
Ein + welches von einem + gefolgt wird, kann nur der
Inkrement Operator sein und nicht 2 'plus' Operationen
hintereinander. (*)
Daher ist
j = i++5;
auch ein Syntax Error und nicht die verkürzte Schreibweise von
j = i + +5;
Aber ehrlich:
a = i+++b;
Wer das so schreibt, sollte mit dem nassen
Fetzen erschlagen werden.
a = i++ + b;
Jetzt sollte alles klar sein :-)
(*) Das war auch der Grund für eine Syntaxänderung in den
Anfangstagen von C. Ihr alle kennt die +=, -=, *= ...
Operatoren.
In den Anfangstagen hiessen die anders: =+, =-, =* etc.
Das hatte aber den Nachteil, dass bei
i=-3;
nicht eindeutig erkennbar war, was gemeint ist. Wollte der
Programmierer:
i =- 3; also i = i - 3;
oder
i = -3;
Der Compiler hat ersteres geparst und anscheinend war des öfteren
letzteres gewollt. Schlussendlich hat man dem Rechnung getragen
und die Zeichen umgedreht.
@ Karl heinz Buchegger (kbuchegg) (Moderator)
>IMHO muss das auch so sein.>Der Compiler muss die längste Kette bilden.>Ein + welches von einem + gefolgt wird, kann nur der>Inkrement Operator sein und nicht 2 'plus' Operationen. (*)
Und? Es kann auch gemeint sein
a = i + ++b;
Ist zwar auch wieder krytischer C-Unsinn, aber prinzipiell denkbar.
>Aber ehrlich: Wer das so schreibt, sollte mit dem nassen>Fetzen erschlagen werden.> a = i++ + b;>Jetzt sollte alles klar sein :-)
Wirklich? Ist es aber nicht so, dass in C Leerzeichen fast KEINE Rolle
spielen zur Trennung von Konstrukten etc.? Und damit die
Leerzeichenversion genauso mehrdeutig ist wie die ohne? Und nur
Klammern das eindeutig definieren?
MfG
Falk
obwohl beides gültige Statements sind, im ersten Fall vorherige
Definition von inta vorausgesetzt.
Somit wird auch klar, warum der Lexer immer das größtmögliche Token
bilden muß, und warum a+++b auf jeden Fall als a++ +b gelesen werden
muß.
Falk Brunner wrote:
> @ Karl heinz Buchegger (kbuchegg) (Moderator)>>>IMHO muss das auch so sein.>>Der Compiler muss die längste Kette bilden.>>Ein + welches von einem + gefolgt wird, kann nur der>>Inkrement Operator sein und nicht 2 'plus' Operationen. (*)>> Und? Es kann auch gemeint sein>> a = i + ++b;>> Ist zwar auch wieder krytischer C-Unsinn, aber prinzipiell denkbar.
Denkbar schon. Gemeint mag der Programmierer das auch haben.
Aber ausdenken kann ich mir viel, entscheidend ist wie die Sache
normiert wurde. Und normiert ist nun mal: die längste Kette
(das größte Token) zählt.
> Wirklich? Ist es aber nicht so, dass in C Leerzeichen fast KEINE Rolle> spielen zur Trennung von Konstrukten etc.?
Die Syntax wurde so hingedreht, dass dies tatsächlich oft der
Fall ist. Aber das heist nicht, dass dem in allen Fällen so ist.
> Und damit die Leerzeichenversion genauso mehrdeutig ist wie die ohne?
Äh. nein. Du verwechselst das mit Fortran. In Fortran ist es
tatsächlich eine der ersten Handlungen des Compilers alle Leerzeichen
in einer Anweisung zu entfernen. Zumindest war das so, bis ich so um
1990 aus Fortran ausgestiegen bin. Keine Ahnung ob modernes Fortran
das immer noch so sieht.
In C wird eine Folge von Whitespace ( = Leerzeichen, Tab, CR/LF aber
auch der klassische /* */ Kommentar) auf ein einzelnes Whitespace-
Character reduziert, bevor dann der Parser die einzelnen Wörter aus
dem Quelltext pickt.
Kurz zurück zu Fortran: Es gibt da eine urban Legend, nach der die
NASA eine Sonde blöd verloren hat. Die Geschichte geht so
Der Programmierer wollte schreiben:
DO 100 I = 1, 20
....
100 CONTINUE
(der Teil .... ist in dem Zusammenhang uninteressant)
Statt dessen hat er aber geschrieben:
DO 100 I = 1. 20
....
100 CONTINUE
Falls es jemand nicht sieht: Der Unterschied ist ein . anstelle des ,
in der DO Zeile.
Warum gab das keinen Syntax Error?
Weil der Compiler als erstes alle Spaces entfernt. Damit erhält er
DO100I=1.20
Da in Fortran standardmässig Variablen implizit definiert werden, hat
der Compiler das als stinknormale Zuweisung aufgefasst: sieht aus
wie eine Zuweisung, ist auch eine. Der Variablen DO100I wird der Wert
1.20 zugewiesen. Wie gesagt werden Variablen implizit definiert, der
Datentyp wird dabei aus dem ersten Buchstaben abgeleitet und 'D' fällt
nun mal in den Bereich für REAL*8, als Gleitkomma. Damit stimmen sogar
die Datentypen links und rechts überein und es gibt noch nicht mal
einen Grund für eine Warnung.
Die ursprüngliche Logik ( das entsprechende Stück würde sich
in C so lesen
for( i = 1; i < 21; ++i )
....
)
war natürlich dahin. Und so hat die NASA durch einen dämlichen
Schreibfehler eine Sonde (die Chronisten sind sich nicht einig
obs zur Venus oder doch zum Merkur gehen sollte) verloren.
Hallo,
damit ich auch bald die letzte Zeile verstanden habe, hier noch einmal
zurück zu meinem Verständnisproblem:
Im ersten Schleifendurchlauf der Do...while Schleife ist serp ja hier:
serpa letzte Byte
+---+---+---+---+---+---+--- ... ---+---+---+
| | | | | | | | | |
+---+---+---+---+---+---+--- ... ---+---+---+
^
|
serp |
+-------+ |
| o--------------------------------------+
+-------+
unsigned char data = *--serp;
Beim nächsten Schleifendurchlauf müsste *--serp ja das hier ergeben:
serpa vorletzte Byte
+---+---+---+---+---+---+--- ... ---+---+---+... ---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+--- ... ---+---+---+... ---+---+---+
^
|
serp |
+-------+ |
| o--------------------------------------+
+-------+
Bedeutet also *--serp dass der Zeiger um Acht Bit nach links verschoben
wird? Also richtung kleineres Byte.
Gruß
technikus
Oder ist in der grafischen Darstellung pro Kasten ein char (also ein
Byte) gemeint?
serpa
+---+---+---+---+---+---+--- ... ---+---+---+
| | | | | | | [7]|[8]|[8]|
+---+---+---+---+---+---+--- ... ---+---+---+
^
|
serp |
+-------+ |
| o--------------------------------------+
+-------+
Also wird bei *--serp immer ein Byte weiter nach links gesprungen, oder
vielmehr drauf gezeigt? Und das Abbild nach data "kopiert" ?
Ich danke euch vielmals für die Mühe! Mann ist C für einen Einsteiger
kryptisch ;-)
Jetzt weiß ich warum die "Laien" Bascom einsetzen - einfach Shiftout und
schwups ist das Byte draussen im Schieberegister.
Gruß
technikus
@ technikus (Gast)
>Bedeutet also *--serp dass der Zeiger um Acht Bit nach links verschoben>wird?
NEIN! Er wird um EINS verringert.
> Also richtung kleineres Byte.
Ja, aber der zeiger zeigt auf Bytes, nicht auf Bits.
>Oder ist in der grafischen Darstellung pro Kasten ein char (also ein>Byte) gemeint?
Ja.
>Also wird bei *--serp immer ein Byte weiter nach links gesprungen, oder>vielmehr drauf gezeigt? Und das Abbild nach data "kopiert" ?
Nicht das Abbild. Das Bytes aus dem RAM, worauf er zeigt. Das Ziel des
Zeigers.
>Ich danke euch vielmals für die Mühe! Mann ist C für einen Einsteiger>kryptisch ;-)
Meine Rede.
MfG
Falk
Falk Brunner wrote:
>>Oder ist in der grafischen Darstellung pro Kasten ein char (also ein>>Byte) gemeint?>> Ja.
@technikus
Aber nur in diesem Fall. Und das auch nur, weil das Array vom
Typ unsigned char ist und daher auch der Pointer ein Pointer
auf unsigned char ist.
Wenn das beispielsweise ein double Array wäre, dann würde ein
Kästchen einen double repräsentieren und der Pointer müsste
klarerweise auch ein Pointer auf double sein
double Array[XYZ];
double* pPtr = Array;
Pointer Arithmetik, und genau darum handelt es sich ja wenn man
einen Pointer erhöht oder verringert, berücksichtigt immer den
Basistyp des Pointers. Bei einem 'unsigned char * pPtr' ist
der Basistyp 'unsigned char'. Bei einem 'double * pPtr' ist der
Basistyp 'double' und bei einem 'struct abc * pPtr' ist der Basistyp
'struct abc'. Bei jeglicher Pointerarithmetik wird immer die sizeof
des Basistyps automatisch mit eingerechnet.
Sei T irgendein beliebiger Datentyp und sei pPtr ein Pointer darauf:
T* pPtr;
dann ist
pPtr + offset;
identisch zu
((unsigned char*)pPtr) + offset * sizeof(T);
Dies ist notwendig, da in C Arrayzugriffe in Form von Zugriffen
über Pointer definiert sind:
T Array[XYZ];
Array[offset] <==> *( Array + offset );
und durch die Art und Weise, wie Pointer Arithmetik definiert ist,
ist damit auch sichergestellt, dass die Größe des Basistyps des
Arrays korrekt in die Arrayindizierung einfliest.