Hallo,
ich nutze einen AT90CAN128. Mein Compiler zeigt mir mittlerweile an,
dass mein Speicher ziemlich voll sein sollte (vermute ich zumindest).
.bss ist 3420 groß und .data hat bereits 5107. Das sollte meinen Ram von
4k um gut das doppelte sprengen, oder?
Ich habe des weiteren gelesen, dass Strings in printf oder in structs
besser ins Flash gelegt werden sollen. Wenn ich mich auf diese beiden
Threads beziehen, dann wird das nicht ohne große Änderungen am Programm
möglich sein:
Beitrag "struct mit strings im flash unterbringen"Beitrag "Strings im Flash"
Gibt es da noch eine besser Möglichkeit meine String-Variablen ins Flash
zu legen?
Bzw. sollte das dann mit einer externen Ram-Erweiterung funktionieren?
Kann das der Compiler schon bei der Generierung berücksichtigen?
Es gibt compiler, die das automatisch können, allerdings nur unter
Verletzung des C-Standards (Pointer sind dann z.B. 3 Bytes lang, etc).
Der GCC hält sich lieber an den Standard, und überlässt das hantieren
mit Flash und EEProm dem Programmierer.
OK. Das ist ja schon mal eine Aussage.
Was genau sagt mir eigentlich .bss? Ich habe gelesen, dass dies die zur
Laufzeit generierten Variablen darstellt. Sprich: Das ist nur ein
Worst-Case Fall, oder? Ich werde ja nicht alle meine Variablen zur
gleichen Zeit nutzen. Wenn ich diese in einer Funktion generiere, dann
sind die beim Verlassen der Funktion ja wieder weg, oder?
Muß ich mich dann nur um .data kümmern, so dass dieser die 4k nicht
überzeigt bzw noch Luft für die Daten von .bss lässt?!
.bss sind Variablen, die beim Programmstart mit Nullen überschrieben
werden.
.data sind Variablen, die beim Programstart einen Startwert aus dem
Flash bekommen.
Sind also beides nicht "Worst-Case" Abschätzungen, sondern der
tatsächliche Bedarf.
Der Rest vom Ram geht für Stack (und Heap, wenn verwendet) drauf, HIER
braucht man die Worst-Case Abschätzung, z.B. max. Rekursionstiefe.
Sonst kann dein Stack über die Variablen "wachsen" und diese
überschreiben...
>Wenn ich mich auf diese beiden>Threads beziehen, dann wird das nicht ohne große Änderungen am Programm>möglich sein
So groß ist der Aufwand für die Strings doch gar nicht. Überall ein PSTR
mit den zugehörigen Klammern eingefügt, dazu per replace die
entsprechenden Funktionen durch ihre _P-Version ersetzt. Ist halt mal
eine Stunde Fleißarbeit.
Was ich nicht nachvollziehen kann, ist, wie man so viel Code schreiben
kann, ohne schon viel früher über das Problem zu stolpern.
Oliver
Was ich nicht nachvollziehen kann, ist, wie man so viel Code schreiben
2
kann, ohne schon viel früher über das Problem zu stolpern.
Die Antwort ist einfach. Alle Teile des Gesamtcodes hab ich schon
irgendwo mal genutzt/geschrieben. Jetzt brauche ich zufälligerweise alle
diese Funktionen für ein neues Projekt, dessen Hardware noch nicht
vorhanden ist. Um mir die Zeit tot zu schalgen mach ich was, was man
eigentlich nicht sollte. Ich schreibe schon mal alles zusammen und mache
einen BigBang Test mit der Hardware, wenn sie denn mal da ist. Was
sicher nicht gut gehen wird :)
PS: Das ganze ist nur so groß geworden, weil ich unmengen von Structs
benutze wobei die meisten noch zu Struckarrays werden. Hab mal bei ein
paar nachgerechnet. Da wird ein "kleines" Array schon mal 1,5k groß.
inbuff liegt auf dem Stack ("Automatic" Variable), d.H. es wird erst
beim Funktionsaufruf bzw betreten des Scopes angelegt.
Die Größe muss zur Compilezeit also nicht feststehen.
Wenn ich die Funktion verlasse wird aber der Speicher wieder frei
gegeben, oder? Mit malloc() wirds dann wohl ähnlich sein.
Erscheinen solche Konstaten dann in .bss oder .data?
Tut mir leid wenn ich da ein bißchen nervend bin, aber mich
interessierts eben :)
Alle automatischen (=lokalen) Variablen, sowie alle per malloc
reservierten Speicherbereiche werden auf dem stack bzw. heap zur
Laufzeit reserviert und freigegeben. Die erscheinen nicht in .bss oder
.data. Dort landen nur globale Variablen.
Oliver
So, was macht der Compiler draus?
Statische variablen werden wie globale behandelt, in der .data-Section
landen also zwei Bytes, goblale_variable2 und statisch2.
Die Variablen ohne initialwert landen in .bss, das sind auch zwei Bytes,
globale_variable1 und statisch2.
Auf dem Stack landen die automatic-Variablen in func, ABER NUR bei
Funktionsaufruf. D.h. am Anfang von func fügt der Compiler Code ein, der
auf dem Stack 2+sizeof(void *) Bytes reserviert, einfach durch
Verschieben des Stack-Pointers.
Ausserdem wird hier Code generiert, um "automatisch2" zu initialisieren.
Beim Verlassen der Funktion wird der Stackpointer wieder zurückgesetzt,
dieser Speicher also wieder freigegeben.
der malloc-Aufruf reserviert Speicher vom Heap (bei AVR-GCC liegt der
üblicherweise zwischen den fix allozierten Speicherbereichen und dem
Stack). Bei Funktionsende wird dieser Speicher NICHT wieder automatisch
freigegeben, das muss der Programmierer selber tun, mit "free"...
>>unsigned char inbuff[Filelength()];>>Fread(inbuff,Filelength());>>funktionieren wobei Filelength() zur Compilerzeit noch nicht definitv>>fest steht. Wie wird das dann da gehandhabt?>inbuff liegt auf dem Stack ("Automatic" Variable), d.H. es wird erst>beim Funktionsaufruf bzw betreten des Scopes angelegt.>Die Größe muss zur Compilezeit also nicht feststehen.
als Gegenargument könnte man einbringen, dass
in keine Funktion eher verzweigt wird, bevor stackframe
nicht eingerichtet ist. Genaudas würde aber FileLength machen.
Ich glaube Standard C = C89 hatte (bis C99) und c++
bis heute, die Bedingung dass Arraylängen compiletime constanten sind.
Wahrscheinlich aus diesem Grund, generell hast Du aber recht,
einfach zu berechnen sind sie schon .. nur halt mit dem Stackrahmen
kommt man in die Quere.
Wenn ich falsch liege, bitte berichtigt mich.
Grüsse,
Daniel
Also speichert er sich den alten Stackpointer in r16,r17 zwischen, ruft
Filesize auf, verringert den Stackpointer um den Rückgabewert (Mit
gesperrten Interrupts), ruft do_something auf, und setzt dannach den
Stackpointer auf die gespeicherten Werte zurück, wieder ohne Interrupts.
Nicht grad schöner Code der dabei rauskommt, funktionieren sollts aber.