in meiner C-Datei erstelle ich mir davon eine Variable
1
p_Rxp_RxHdr;
1
for(i=0;i<8;i++){
2
3
p_RxHdr[i].p_DataBuf=NULL;
4
p_RxHdr[i].HdrNbr=i;
5
6
}
Im Prinzip hab ich 8 Datensätze von diesem Struct Data und möchte diese
in dieser for-Schleife mit den Ausgangswerten initialisieren. Kann man
das so machen?
Ist das das gleiche, als wenn ich vom Typ data mehrere Variablen
deklariere?
in meiner version bekomm ich keinerlei fehlermeldungen angezeigt, nur
bin ich mir nicht ganz sicher ob in der for-schleife tatsächlich mehrere
variablen davon erzeugt werden bzw. ein array.
Bernd
p_Rx p_RxHdr;
erzeugt garkeine Variable vom Typ struct data, sondern einen Pointer
darauf. Da du den Pointer noch nicht einmal initialisierst, wird deine
for-Schleife höchstwahrscheinlich beim ersten Zugriff über p_RxHdr
abrauchen.
Der Compiler prüft nur, ob das, was du schreibst, syntaktisch richtig
ist; wenn er keinen Fehler meldet, heißt das noch lange nicht, daß der
Quelltext nicht völliger Unsinn ist.
Der Satz: "Draußen ist es kälter, als morgen." ist syntaktisch korrektes
Deutsch, aber semantisch Unsinn...
d.h. in der for-schleife erzeuge ich einfach mehrere zeiger (p__RxHdr0,
p__RxHdr1 usw. ), die alle auf die gleiche struktur data zeigen, aber
keine variablen von der struktur data selbst sind.
>Da du den Pointer noch nicht einmal initialisierst
ok - der pointer müsste dann noch intialisiert werden mit einer
Speicheradresse.
Bernd
Hi,
wenn ich da mal was ergänzen darf:
Das typedef deklariert einen Typen namens p_Rx als Zeiger auf eine
Struktur namens Data.
Mit p_Rx p_RxHdr; wird ein Zeiger auf solche eine Struktur alloziiert,
aber nicht, wie Uhu Uhuhu schon richtig sagt, Speicherplatz für die
Struktur.
Viele Compiler gucken nicht darauf, ob der Speicherplatz, auf den
zugegriffen wird auch tatsächlich alloziiert ist. Teilweise liegt das
daran, das angenommen wird, man könne nicht wissen, was über den Linker
noch dazu kommt.
Das könnte beispielsweise eine Dekklaration oder ein alloc sein.
Andere Tools, wie Lint warnen aber vor solchen Fällen.
Ich denke der Knackpunkt liegt hier darin, das man strikt darauf achten
muss, das Typedef einen Typnamen deklariert, keine Variablen. Dein * vor
dem p_Rx gehört also dem Sinn nach zu struct data.
Gruss
Oops
Bernd Schuster wrote:
> d.h. in der for-schleife erzeuge ich einfach mehrere zeiger (p__RxHdr0,> p__RxHdr1 usw. ), die alle auf die gleiche struktur data zeigen, aber> keine variablen von der struktur data selbst sind.
Die for-Schleife erzeugt nicht mehrere Pointer, sondern sie benutzt nur
den einen, den du definiert hast, und macht damit Adressarithmetik.
Du solltest mal in deinem C-Buch die Kapitel über Pointer, Arrays und
Adressarithmetik nachlesen.
hab mir ein bsp von atmel angeschaut, in der die das so realisiert haben
(ich hoffe ich hab keinen wichtigen code-teil vergessen).
Einfach um zu sehen, warum das hier so geht und es keine
Speicherprobleme etc. gibt:
das ist deren struct:
.addr beinhaltet z.b. die Daten, die über die Ethernet Schnittstelle an
den µController kommen. Und .size nur die Information ob dieser Buffer
leer oder voll ist.
Ist das gut programmiert - oder könnte diese Herangehensweise zu
Problemen bezüglich Speicherzugriffsfehler etc. führen? Weil eine
Variable wird von der struct auch nicht erzeugt, so dass für diese
Speicher alloziiert werdne könnte?
Bernd
Sowas benutzt man nur für Datenbereiche, deren Adresse von der Hardware
vorgegeben ist.
Für normale Variable überläßt man dem Compiler die Adressraumverwaltung,
denn das Programm würde sonst sehr schnell unpflegbar.
Hi Bernd.
Ich setze mal voraus, das der gesamte Code keinen Fehler enthält.
Dann ist Dein Code-Teil unvollständig. Denn es fehlt wie gesagt, die
Definition des Speichers an der Address 0x0x20010000.
Ich vermute mal es handelt sich hier um einen Memory mapped I/O für
Ethernet.
Dann wird irgendwo in den Projektdateien die Definition enthalten sein.
Gruss
Oops
>Denn es fehlt wie gesagt, die Definition des Speichers an der Address >0x0x20010000
dass ist eine speicheradresse, die im internen RAM oder externen SDRAM
(wie in diesem Fall) liegen kann. Dorthin kommen die Daten von der
Ethernet Schnittstelle. Sprich diese Adresse ist nicht vorgegeben von
der Hardware.
>Sowas benutzt man nur für Datenbereiche, deren Adresse von der Hardware>vorgegeben ist.
d.h. hier muss ich nicht zuvor speicher reservieren?
Bernd
>>Sowas benutzt man nur für Datenbereiche, deren Adresse von der Hardware>>vorgegeben ist.>> d.h. hier muss ich nicht zuvor speicher reservieren?
Ja. Der Speicher muß vorhanden sein und du solltest die Methode als den
Sonderfall betrachten, der es ist.
@ Uhu Uhuhu
>Bernd hat die Definition angegeben:>#define AT91C_EMAC_TDLIST_BASE 0x20010000
Tut mir leid, aber obige Anweisung wird vom Präprozessor interpretiert
und nicht vom Compiler. Schon deswegen ist das keine Definition die
Speicherplatz reserviert. Es ist ein Präprozessor-Definition.
Falls Du aber meintest, das er "uns" (als Forumsleser) damit mitgeteilt
hat wo der Speicher liegt, liegen könnte oder liegen sollte, hast Du
natürlich recht. Aber der Compiler muss das wissen, nicht wir.
Gruss
Oops
Bernd:
> ein ptr auf die struct:>> AT91PS_TdDescriptor tdList = (AT91PS_TdDescriptor)AT91C_EMAC_TDLIST_BASE;>> wobei dieser word aligned sein muss...>> #define AT91C_EMAC_TDLIST_BASE 0x20010000
Da stehts doch - ist zwar in umgekehrter Reihenfolge, aber es ist ja
auch kein Programm, sondern eine verbale Beschreibung des Codes...
wie kann man denn für einen bestimmten bereich speicher alloziieren,
wenn die Pakete an die Speicherstelle 0x20010000 ff. geliefert werden?
Ich weiß wie groß der Speicherbereich sein wird und ab welcher Adresse
er anfängt`.
malloc ist mir ein Begriff.
Bernd
Das #define definiert die Adresse.
(AT91PS_TdDescriptor)AT91C_EMAC_TDLIST_BASE
casted die Konstante in einen AT91PS_TdDescriptor.
Damit zeigt tdList auf die Adresse 0x20010000
Ohne Umweg über das #define - was man aber tunlichst nicht machen soll -
sieht es so aus:
Bernd Schuster wrote:
> aber damit definiere ich ja nur den startpunkt im speicher und nicht den> ganzen speicherbereich, oder?
Jain. Du 'behauptest', daß auf der Adresse AT91C_EMAC_TDLIST_BASE ein
Objekt vom Typ AT91S_TdDescriptor liegt. Damit has du implizit natürlich
eine Längenangabe, nämlich sizeof (AT91S_TdDescriptor).
Wegen der Strukturähnlichkeit von Array und Pointer kannst du relativ zu
deinem Pointer ein ganzes Array von AT91S_TdDescriptor-Objekten
adressieren, z.B. so:
1
*tdList// dereferenziert das Objekt auf tdList
2
tdList[0]// dto.
3
4
*(tdList+3)// dereferenziert das 4. Objekt ab tdList
5
tdList[3]// dto.
6
7
*(tdList-5)// dereferenziert das 5. Objekt unterhalb tdList
8
tdList[-5]// dto.
Dem Compiler ist dabei egal, ob auf den angesprochenen Adressen Speicher
liegt, oder nicht - deswegen meine Formulierung: "du 'behauptest'". Die
Längenangabe relativiert sich damit wieder sehr...
> Du solltest mal in deinem C-Buch die Kapitel über Pointer, Arrays und> Adressarithmetik nachlesen.
Solltest du unbedingt tun!!!
also wie ich das safe programmiere mit den buffern für die
ethernet-pakete weiß ich noch nicht so genau...
mit sizeof (struct data) bekomm ich den speicherplatz raus, der von
einem Buffer benötigt wird, die Startadresse vom Buffer habe ich, aber
wie ich diesen Speicher dann wirklich absichern kann - wahrscheinlich
macht das dann wirklich alles der Compiler und ich mach mir vllt zu
viele gedanken...
Bernd
Bernd Schuster wrote:
> mit sizeof (struct data) bekomm ich den speicherplatz raus, der von> einem Buffer benötigt wird, die Startadresse vom Buffer habe ich, aber> wie ich diesen Speicher dann wirklich absichern kann - wahrscheinlich> macht das dann wirklich alles der Compiler und ich mach mir vllt zu> viele gedanken...
Nein, der Compiler macht in dem Fall garnichts. Du darfst beliebigen
Unsinn schreiben, solange der syntaktisch korrekt ist, regt der Compiler
sich nicht auf.
Es ist also Aufgabe des C-Programmierers, dafür zu sorgen, daß
physikalische Pufferlängen nicht überschritten werden.
Nun kann es aber sein, daß ein großer Puffer nur wenig 'echte' Daten
enthält. Man löst das Problem dadurch, daß im Programm ständig aktuelle
Angaben darüber geführt werden, wo das logische Ende der Daten ist.
Paradebeispiel sind Strings:
1
charPuffer[1024]="Hallo";
Dieses Codeschnipsel legt einen Puffer mit 1024 char an - das ist die
physikalische Größe.
Darin liegt der Text "Hallo", bestehend aus den 5 Buchstaben, die du
siehst und ein abschließendes \0 - Character.
1
unsignedphysSize=sizeofPuffer;// 1024
2
unsignedlogSize=strlen(Puffer);// 5 - \0 wird nicht mitgezählt.
das weiß ich, aber wenn ich eine feste startadresse habe im speicher,
die den Anfang des Buffers kennzeichnet, sowie dessen Größe ich ja auch
weiß und somit auch entsprechend reservieren könnte, aber wie sage ich
(code) dass dieser Speicher genau ab dieser Adresse für den Buffer
belegt werden soll.
Also diesen Buffer auf eine festgelegte Adressbereich mappen kann
Bernd
Du belegst garnichts - du weißt, wo der Puffer beginnt und wie lang er
ist. Das mußt du beachten, wenn du die Programmteile schreibst, die mit
dem Puffer arbeiten.
malloc ist dafür auf jeden Fall nicht geeignet, weil es sich um einen
Hardwarepuffer mit fester Adresse und Länge handelt und der deswegen
nicht Teil des Heap sein darf. (Im Heap dürfen nur allgemeinverwendbare
Speicherbereiche liegen, weil der Heapmanager (malloc ist ein Teil
davon) selbst entscheidet, mit welchem Speicherbereich eine Anfrage
erfüllt wird.)
Lies das nochmal: Beitrag "Re: struct: mehrere variablen erstellen"
>Du belegst garnichts - du weißt, wo der Puffer beginnt und wie lang er>ist. Das mußt du beachten, wenn du die Programmteile schreibst, die mit>dem Puffer arbeiten.
ok - d.h. so wie das atmel programmiert hat funktioniert das auf jeden
Fall safe. Nur muss ich als Programmierer wissen wo dieser Buffer im
Speicher liegt und dann entsprechend mit den Zeigern auf diesen Buffer
zugreifen um die relevanten Informationen zu erhalten, aber das wars
dann auch.
>malloc ist dafür auf jeden Fall nicht geeignet, weil es sich um einen>Hardwarepuffer mit fester Adresse
d.h. eigentlich benötigt man malloc gar nicht - bzw. nur für Buffer, die
von der Hardware schon bereitgestellt werden, um z.B. darin die 8Bits
der seriellen Schnittstelle zu speichern... mich als Programmierer
betrifft aber Malloc gar nicht, weil der Hardwarebuffer schon vorgegeben
und reserviert ist, oder?
Und wenn ich mit struct eine variable anlege, wird der speicher dafür
gleich mit reserviert - und in diesem Fall ist es mir als Programmierer
egal wo der Speicherplatz dafür reserviert wird; wird alles für mich
erledigt.
Bernd
> d.h. eigentlich benötigt man malloc gar nicht - bzw. nur für Buffer, die> von der Hardware schon bereitgestellt werden, um z.B. darin die 8Bits> der seriellen Schnittstelle zu speichern... mich als Programmierer> betrifft aber Malloc gar nicht, weil der Hardwarebuffer schon vorgegeben> und reserviert ist, oder?
Nein. Die Hardwarepuffer müssen von der Verwaltung durch den
Heapmanager ausgeschlossen sein. Sie sind dem Heapmanger unbekannt und
er hat damit nichts zu tun.
Auf Windows-PCs gibt es das auch: Der Adressraum einer Anwendung ist
maximal 3 GB, während ein 32-Bit-Rechner 4 GB 'kann'. Im obersten GB
'liegen' u.a. die Hardware-Puffer für PCI-Geräte, das BIOS-Rom u.ä.
Stichwort: Memory mapped I/O.
'liegen' deshalb, weil diese Speicherbereiche von der MMU (Memory
Managment Unit) dort hinein gemapt werden. Auf einem anderen OS können
sie irgendwo anders liegen
vielen dank für die informationen... das mit den Hardwarepuffern hab ich
jetzt verstanden.
Der Heap und Stack befindet sich immer auf dem internen RAM - oder kann
dieser sich auch auf einem externen SDRAM befinden? Im Startup-Skript
definiere ich ja nur die Größe des Heaps und des Stacks aber nicht seine
Position. (wird dann wahrscheinlich im linker-skript festgelegt).
Und das hier funktioniert deshalb, weil ich im externen SDRAM selbst
bestimme wo welche Daten gespeichert werden sollen - und nicht das O/S
etc.
Ich glaub ich muss mir mal die genaue Definition von Heapmanager und die
Speicherverwaltung anschauen - kennst du dazu hilfreiche suchbegriffe
(bei denen erklärt wird, wer sich wann über die Aufteilung des Speichers
und dessen Inhalt Gedanken machen muss)?
Bernd