Guten Morgen (:
Ich habe ein da mal ein Problem..
Und zwar wenn ich in der Funktion versuche, mit malloc() Speicher frei
zu schaufeln, funktioniert das ein paar mal.. ab und zu aber stürzt mir
meine App. ab.
Mit einer festen Speichergröße (also einem Array) klappt alles wie es
soll.
Mache ich was Grundlegendes falsch?
Jan H. schrieb:> Und zwar wenn ich in der Funktion versuche, mit malloc() Speicher frei> zu schaufeln, funktioniert das ein paar mal.. ab und zu aber stürzt mir> meine App. ab.
Dynamische Speicherverwaltung kann man auf einem µC eigentlich kaum
verwenden.
Erstens gibt es nirgends ein free, d.h. der RAM wird ratzfatz
aufgebraucht.
Und zweitens funktioniert free ohne Speicherverwaltung nicht, d.h. der
freigegebene RAM kann nicht wieder genutzt werden.
Du solltest alles als statische Arrays deklarieren oder ein einziges mal
einen malloc machen und den Speicherbereich dann immer wieder
weiterverwenden. Dann kann man aber auch gleich ersteres machen :)
Jan H. schrieb:> Mampf F. schrieb:>> Erstens gibt es nirgends ein free, d.h. der RAM wird ratzfatz>> aufgebraucht.>> Ist doch vorhanden?
Ah okay, dennoch gilt der Rest ;-)
Soweit ich es kenne, sollten malloc() und free() gehen.
Nur ist die Gefahr von Problemen größer, da weniger Speicher überhaupt
dafür verwendet werden kann, und dieser dann stark fragmentiert werden
kann.
In dem Programm oben werden immer genau 10 Bytes alloziert, das könnte
mit einem statischen Buffer besser gehen.
Ausserdem gibt es returns vor dem free(), so dass Speichern verloren
gehen kann.
Und für mich heisst das immer noch Programm und nicht App.
Den Speicher auf dem Stack zu legen wäre hier auch nicht falsch , die
Größe ist ja immer 10. und der Speicher wird nach dem Rückkehren aus der
Funktion nicht mehr benötigt
Ich hatte vor ca. 10 Jahren eine Art Schnittstellenkonverter geschrieben
der einen Datenstrom in Teile flexibler Länge aufsplittete, die Elemente
in einer verketteten Liste zwischenspeicherte und in anderer
Reihenfolge/Dimension/Geschwindigkeit usw. wieder ausgab.
Ich habe dazu ohne daran großartig zu zweifeln malloc/free der avr-libc
benutzt ....Jörg hat die lib dann mit mir debuggt ..sie sollte also
damals dann weitgehend fehlerfrei gewesen sein was sie zu Beginn meiner
Arbeiten nicht war. In meinem Programm wurde aber "nach einem Durchlauf"
jeweils die gesamte Liste wieder frei gegeben..da funktionierte auch die
Defragemntierung das RAMs und der lief nicht langsam zu.
Das Ganze war ein paar Jahre in der Industrie auf Atmega644p in mehreren
Varianten problemlos im Einsatz.
Schaue mal beim Programmlauf nach folgenden Variablen, Freelist und
heap...
Die Meinung das man dynamischen Speicher auf einem Mikro nicht nutzen
kann ist hier stark vertreten, aber Blödsinn, es funktioniert und ich
hatte damals keine andere Wahl. In "rechteckige" Felder verpackt hätten
die Daten keinen Platz im Speicher gehabt.
Der Vorschlag die Daten auf den Stack zu legen ist auch eine praktikable
Variante, aber wie auch mit malloc/free muß man höllisch aufpassen den
Speicher symmetrisch mit den richtigen Pointern zu behabndeln..
Gruß,
Holm
Holm T. schrieb:> Die Meinung das man dynamischen Speicher auf einem Mikro nicht nutzen> kann ist hier stark vertreten, aber Blödsinn, ...
Naja...
Einen fragmentierten Speicher wird man nur durch einen Reset wieder los.
Ebenso verhält es sich mit Speicherleichen auf dem Heap.
Ich vertrete die Meinung:
1. verzichte darauf, wenn möglich
2. erhöhte Aufmerksamkeit/Disziplin bei der Verwendung.
Wie derbe die Verwendung nach hinten los gehen kann, sieht man an der
Eingangsfrage.
Oder anders:
> Wenn der Esel zu wenig Probleme hat,> dann geht er aufs Eis.
Rufus Τ. F. schrieb:> Jan H. schrieb:>> (char*)malloc(sizeof(char)*10);>> Der typecast ist überflüssig, und sizeof char ist per Definition immer> 1.
Danke für den Hinweis.
Root schrieb:> Den Speicher auf dem Stack zu legen wäre hier auch nicht falsch , die> Größe ist ja immer 10. und der Speicher wird nach dem Rückkehren aus der> Funktion nicht mehr benötigt
Das scheint beim TO noch nicht angekommen zu sein.
Ausserdem ist nicht unter allen Bedingungen gewährleistet dass
nach dem malloc() auch später ein free() ausgeführt wird.
Siehe
Das Problem loest man doch ganz anders, ohne kopieren, direkt auf dem
Kommunikationsringbuffer. Eine Zustandsmaschine, die auf ein Null, oder
Timeout wartet, und falls das Null kam, auf den vorgaengigen String
reagiert.
Jan H. schrieb:> cmdBeginn = strstr(inBuff,cmdBeginn_);
Solche Zeilen mag ich gar nicht....
In der Regel werfe ich solche Programmtexte weg.
Verweigere das weiter lesen.
Das Problem ist nicht strstr()
Sondern die Bezeichnerähnlichkeit: cmdBeginn vs. cmdBeginn_
Ich halte sowas für eine glänzende Methode, sich selber ein Fettnäpfchen
vor die Füße zu stellen.
Arduino F. schrieb:> Einen fragmentierten Speicher wird man nur durch einen Reset wieder los.> Ebenso verhält es sich mit Speicherleichen auf dem Heap.
Malloc heißt nicht, dass man fragmentierten Speicher hat. Ich finde
fragmentlose dynamische Speicherverwaltung ist vorzuziehen, wenn die
Software dadurch an Übersicht gewinnt.
avr schrieb:> wenn die Software dadurch an Übersicht gewinnt.
Bei dem obigen Codefetzen, gibt es einige Stellen, wo man Übersicht dazu
gewinnen könnte.
Der Verzicht von malloc() und free() würde dazu gehören, da sie hier
völlig unnötig sind.
(so wie ich das sehe)
Von dem Code müssen wir auch nicht reden, da stimme ich dir zu. Nur
allgemein spricht bei richtiger Verwendung nichts gegen dynamische
Speicherverwaltung auf Mikrocontrollern.
Jan H. schrieb:> Ich habe ein da mal ein Problem
Mehr als das.
Erstens gibt es keine App auf Mega32u4.
Zweitens kann man unter C zwar malloc verwenden, aber nur wenn der heap
zuvor eingerichtet wurde. Wie gross hast du ihn denn eingerichtet ?
Drittens hast du
Jan H. schrieb:> mit malloc() Speicher frei zu schaufeln
offenkundig ein massives Verständnisproblem was malloc tut. Eher das
Gegenteil von freischaufeln, nämlich belegen. Je mehr malloc man macht,
um so weniger freien Speicher hat man.
Auch würde ich den Unsinn mit den gleichen Namen nur mal mit _ und mal
ohne, sein lassen, das ist obfurscation, kein sinnvoller Stil.
Auch stellt sich die Frage, warum cmdBeginn_ fest für 9 Zeichen
ausgelegt wird, was ist wenn in srchCmd mehr drinstehen ?
Und wenn man ein x in abdxxxdef sucht, warum kopiert man ganz abcxxxdef
und nullt dann bei abcxxx das def weg ?
Klingt falsch.
Ein Grundlagenbuch über Programmierung wäre wohl angeraten.
Programmieren ist so einfach wie Lego, man muss nur vorgegebene
Bausteine zum Gesamtwerk zusammenklipsen.
Du musst wohl erst lernen was Legosteine sind.
Vor den vielen Fehler- return nach dem malloc muss z.B. auch ein free
hin.
avr schrieb:> Malloc heißt nicht, dass man fragmentierten Speicher hat
Doch, in C schon.
> Malloc heißt nicht, dass man fragmentierten Speicher hat> Doch, in C schon.
Nein nicht unbedingt. Es kommt auf die Größe der Blöcke und die
Reihenfolge an, in der man den Speicher belegt und wieder freigibt.
Stefan U. schrieb:> und die> Reihenfolge an, in der man den Speicher belegt und wieder freigibt.
Das ist ja das doofe....
Wer will da schon Buch führen müssen.
Stefan U. schrieb:> Nein nicht unbedingt. Es kommt auf die Größe der Blöcke und die> Reihenfolge an, in der man den Speicher belegt und wieder freigibt.
Wenn man zur Designzeit schon weiß welche Blöcke man wie groß braucht,
dann kann man sich in den meisten Fällen auch ganz die dynamische
Speicherverwaltung sparen.
avr schrieb:> Malloc heißt nicht, dass man fragmentierten Speicher hat. Ich finde> fragmentlose dynamische Speicherverwaltung ist vorzuziehen, wenn die> Software dadurch an Übersicht gewinnt.
Daß die dynamische Speicherverwaltung auch Code und Datenoverhead bringt
ist dir aber auch bewusst?
Und wie gesagt, wenn ich von vorneherein weiss was ich mit malloc
brauche, dann kann ich in 80-95% der Fälle den Speicher auch gleich
statisch belegen. Und das durchaus auch übersichtlich, wohingegen ein
sauberes free() handling den Code durchaus unübersichtlicher machen
kann.
Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht
soweit, daß er sich an dynamische Speicherverwaltung bei doch so
besonderen Umständen wagen sollte.
MaWin schrieb:> Vor den vielen Fehler- return nach dem malloc muss z.B. auch ein free> hin.
Da gibt es ein nettes Konstrukt in C, das man verwenden kann ...
Der Andere schrieb:> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht> soweit, daß er sich an dynamische Speicherverwaltung bei doch so> besonderen Umständen wagen sollte.
+1
Der Andere schrieb:> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht> soweit, daß er sich an dynamische Speicherverwaltung bei doch so> besonderen Umständen wagen sollte.
Das sind immer die stärksten ;)
Ich nenne es nun mal "Applikation".
Vill. solltest du vorher mal deinen Horizont erweitern ;)
Es stürzt nicht ab sondern führt zu nicht gewollten Verhalten. Da du
auch nicht prüfst ob der Bereich gültig ist den dir malloc übergibt.
Denn so könnte man das abfangen. Beim ARM landet man im Defaulthandler.
In diesem kann man dann dafür sorgen daß die Anwendung nicht Amok läuft.
Jan H. schrieb:> Der Andere schrieb:>> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht>> soweit, daß er sich an dynamische Speicherverwaltung bei doch so>> besonderen Umständen wagen sollte.>> Das sind immer die stärksten ;)> Ich nenne es nun mal "Applikation".>> Vill. solltest du vorher mal deinen Horizont erweitern ;)
Applikation:
Als Anwendungssoftware (auch Anwendungsprogramm, kurz Anwendung oder
Applikation) werden Computerprogramme bezeichnet, die genutzt werden, um
eine nützliche oder gewünschte nicht systemtechnische Funktionalität
zu bearbeiten oder zu unterstützen.
Firmware:
Unter Firmware (engl. firm ‚fest‘) versteht man Software, die in
elektronischen Geräten eingebettet ist. Sie ist zumeist in einem
Flash-Speicher, einem EPROM, EEPROM oder ROM gespeichert und durch den
Anwender nicht oder nur mit speziellen Mitteln bzw. Funktionen
austauschbar.
Ich frage mich, wer hier seinen Horizont erweitern sollte...
mfg
Marco H. schrieb:> Es stürzt nicht ab sondern führt zu nicht gewollten Verhalten.
Ach...
Da machst du aber feine Unterschiede...
Keiner will hier AVRs vom Tisch auf die Erde fallen lassen..
Marco H. schrieb:> Da du> auch nicht prüfst ob der Bereich gültig ist den dir malloc übergibt.> Denn so könnte man das abfangen.
Wird doch gemacht!
Marco H. schrieb:> Beim ARM landet man im Defaulthandler.
Wir sind hier aber nicht ARM.
Beim AVR gibts, dank gänzlich fehlendem Speicherschutz, keine
zuverlässige Möglichkeit Heap-Stack Kollisionen zu erkennen.
Jan H. schrieb:> Vill. solltest du vorher mal deinen Horizont erweitern ;)
Mag sein, du solltest auf jeden Fall deine Programmierkenntnisse
erweitern.
Solange du völlig unnötig so dicke Speicherleaks auf einem kleinen µC
bastelst obwohl man das mit einer popeligen lokalen Variablen hätte
lösen können nehme ich vor dir ehrlich gesagt wenig Belehrung an.
An deiner Stelle wäre ich soooo klein mit Hut und würde mich bei den
Usern "Root" und "Mitlesa" bedanken.
Der Andere schrieb:> Daß die dynamische Speicherverwaltung auch Code und Datenoverhead bringt> ist dir aber auch bewusst?
Der geht im Rauschen unter. Natürlich geht es auch statisch. Aber
wartungsfreundlicher geht es mit malloc. Wenn ich eine z.b. fifo Objekt
habe, möchte ich nicht erst ein Array als Puffer dafür banlegen, sondern
direkt die Größe übergeben.
Quasi fifo* f = create_fifo(128);
Die Puffer werden einmal dynamisch angelegt. Vielleicht gefällt das dir
nicht, aber weniger und übersichtlicherer Code ist mir wichtiger als ein
paar Bytes ram.
Und auch in c++ möchte ich die Größe auch nicht als Template parameter
haben, weil damit das die Codegröße erhöht, wenn mehrere fifos genutzt
werden. Besonders wenn diese in anderen Klassen/Funktionen genutzt
werden.
avr schrieb:> Natürlich geht es auch statisch. Aber> wartungsfreundlicher geht es mit malloc.
Klar, wie man im Beispiel vom TO sieht ist das superwartungsfreundlich.
Sprich es ist freundlich für den der den Code warten muss denn er hat
ordentlich zu tun bis er alle Speicherleaks gefunden hat.
Nur für den Kunden sind die vielen Abstürze nicht so freundlich.
:-p
avr schrieb:> Quasi fifo* f = create_fifo(128);
Wir haben hier von 8 Bit µC geredet, nicht von 32 Bit oder PC Software
avr schrieb:> Quasi fifo* f = create_fifo(128);> Die Puffer werden einmal dynamisch angelegt. Vielleicht gefällt das dir> nicht, aber weniger und übersichtlicherer Code ist mir wichtiger als ein> paar Bytes ram.
Allein die Behauptung, dynmaische Speicherverwaltung wäre per se
übersichtlicher oder sauberer ist doch Unsinn. Diese Prämisse würde ich
erstmal verneinen.
Wenn der benötigte maximale Speicher von vornherein bekannt ist, macht
es einfach keinen Sinn diesen NICHT statisch anzulegen. Das ist
übersichtlich und lässt einen den belegten Speicher direkt einsehen.
Beim klassischen µC Projekt steht nun mal der Speicher meistens fest.
Und auch wenn ich mehrere FIFO Objekte benötigte, weiß ich im vorraus
wieviele und allokiere das Objekt oder die Struktur entsprechend oft,
aber trotzdem statisch.
Selbst wenn die benötigte Anzahl erst zur Laufzeit bekannt werden
sollte, weiß ich trotzdem wie viele es maximal sein dürfen. Und die kann
ich dann auch statisch anlegen weil ich den übrigen Speicher für nichts
aufsparen kann.
Der seltene Fall wo dynmische Verwatlung sinn machen kann, ist eben der,
wo zur Laufzeit entscheiden wird, wie viele Objekte vom Typ X und
wieviele Objekte vom Typ Y benötigt werden.
Dann kann ich eben nicht einfach statisch maximal den Speicher voll
machen sondern muss in der Tat dynamisch arbeiten.
Aber wie gesagt, dieser Fall kommt im klassischen µC Umfeld nicht os
häufig vor.
Felix F. schrieb:> Applikation:> Als Anwendungssoftware (auch Anwendungsprogramm, kurz Anwendung oder> Applikation) werden Computerprogramme bezeichnet, die genutzt werden, um> eine nützliche oder gewünschte nicht systemtechnische Funktionalität> zu bearbeiten oder zu unterstützen.
Tatsächlich spricht man auch bei µCs von Anwendung bzw. Applikation z.B.
bei Steuergeräten, um den Code, der die eigentliche Funktionalität
umsetzt, vom Rahmen-Code zu unterscheiden, der sich um die
low-level-Dinge wie Kommunikation oder Zyklus-Steuerung kümmert.
> Ich frage mich, wer hier seinen Horizont erweitern sollte...
Ich mich auch.
Arduino F. schrieb:> Marco H. schrieb:>> Es stürzt nicht ab sondern führt zu nicht gewollten Verhalten.> Ach...> Da machst du aber feine Unterschiede...
Nun, unter Absturz verstehe ich, dass das Betriebssystem das Programm
terminiert und aus dem Speicher entfernt, weil es irgendeine unzulässige
Aktion durchführen will - von mir aus auch noch, wenn das Programm sich
per abort() beendet, weil ein assert fehlgeschlagen oder eine
unbehandelte Exception aufgetreten ist. Bei einem AVR gibt's das aber
natürlich nicht, und es läuft immer irgendwie weiter. Es kann nicht
terminiert werden, außer durch Trennen der Stromversorgung.
Daher wäre dann die Frage, was du bei einem AVR unter "abstürzen"
verstehst.
> Beim AVR gibts, dank gänzlich fehlendem Speicherschutz, keine> zuverlässige Möglichkeit Heap-Stack Kollisionen zu erkennen.
Deshalb ist statischer Speicher geschickter. Bei dem weiß man schon zur
Compilezeit, wieviel davon insgesamt benötigt wird.
avr schrieb:> Der Andere schrieb:>> Daß die dynamische Speicherverwaltung auch Code und Datenoverhead bringt>> ist dir aber auch bewusst?>> Der geht im Rauschen unter.
Auf dem PC schon, aber auf einem kleinen 8-Bitter nicht.
> Natürlich geht es auch statisch. Aber wartungsfreundlicher geht es mit> malloc.
Was soll daran wartungsfreundlicher sein? Der obige Code enthält ein
Memory-Leak, nur weil etwas dynamisch allokiert wird, dessen Größe
eigentlich zur Compilezeit schon feststeht. Im obigen Fall hat der
dynamische Speicher genau Null Vorteil und macht nur Probleme.
> Wenn ich eine z.b. fifo Objekt habe, möchte ich nicht erst ein Array als> Puffer dafür banlegen, sondern direkt die Größe übergeben.
Darum geht es hier aber gar nicht. Hier geht es um eine Funktion, die an
ihrem Anfang ein einfaches Array aus 10 Bytes dynamisch allokiert, es
dann zwischendurch benutzt und an ihrem Ende (manchmal) wieder freigibt.
> Die Puffer werden einmal dynamisch angelegt. Vielleicht gefällt das dir> nicht, aber weniger und übersichtlicherer Code ist mir wichtiger als ein> paar Bytes ram.
Wenn man nur "ein paar Bytes ram" hat, können die plötzlich deutlich an
Wichtigkeit gewinnen.
> Und auch in c++ möchte ich die Größe auch nicht als Template parameter> haben, weil damit das die Codegröße erhöht, wenn mehrere fifos genutzt> werden.
Wie kommst du darauf? Vom Hörensagen, oder hast du das getestet?
> Besonders wenn diese in anderen Klassen/Funktionen genutzt> werden.
Warum sollte es einen Unterschied machen, wo die genutzt werden?
Arduino F. schrieb:> Holm T. schrieb:>> Die Meinung das man dynamischen Speicher auf einem Mikro nicht nutzen>> kann ist hier stark vertreten, aber Blödsinn, ...>> Naja...> Einen fragmentierten Speicher wird man nur durch einen Reset wieder los.> Ebenso verhält es sich mit Speicherleichen auf dem Heap.
..meint ein "Arduino Fanboy"?
>>> Ich vertrete die Meinung:> 1. verzichte darauf, wenn möglich> 2. erhöhte Aufmerksamkeit/Disziplin bei der Verwendung.>> Wie derbe die Verwendung nach hinten los gehen kann, sieht man an der> Eingangsfrage.>> Oder anders:>> Wenn der Esel zu wenig Probleme hat,>> dann geht er aufs Eis.
..und verbreitet hier seltsame Weisheiten..
Gruß,
Holm
Mampf F. schrieb:> Da gibt es ein nettes Konstrukt in C, das man verwenden kann ...
Was die Leute alles so für Verrenkungen machen, nur damit sie einen
gezielten Sprung machen können, ohne das böse Wort „goto“ hinschreiben
zu müssen. :-))
Bezüglich des TE: solange es wirklich immer 10 Bytes sind, legt man
das wirklich besser auf dem Stack ab. Allerdings hat man dort
keinerlei Schutz dagegen, dass einem der Stack dann nicht in die
globalen bzw. statischen Variablen reinrennt. malloc() gibt sich da
wenigstens noch ein bisschen Mühe, den Überlauf-Fall abzusichern (und
gibt dann 0 zurück).
Warum man mit der blöden These, dynamischen Speicher auf Controllern
komplett zu vermeiden, nicht immer weiterkommt, hat Holm ja bereits
geschrieben.
Jan H. schrieb:> //char cmdBeginn_[26] = "";>> strcpy(cmdBeginn_,srchCmd);
Irgendwie passen die 10 allozierten Bytes überhaupt nicht zu den 26
im Kommentar. Außerdem würde ich dort natürlich nur dann auf
strncpy() verzichten, wenn unter allen Umständen durch den Rest des
Programms technisch sichergestellt ist, dass der String in srchCmd
niemals länger als 9 Zeichen werden kann.
Cyblord -. schrieb:> Der Andere schrieb:>> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht>> soweit, daß er sich an dynamische Speicherverwaltung bei doch so>> besonderen Umständen wagen sollte.>> +1
AVRstudio legte zumindest früher den Code irgendwie in "app" ab..
Wenn App ne Abkrüzung von Applikation ist kann man es noch durchgehen
lassen..
Gruß,
Holm
Arduino F. schrieb:> Beim AVR gibts, dank gänzlich fehlendem Speicherschutz, keine> zuverlässige Möglichkeit Heap-Stack Kollisionen zu erkennen.
Jein: das malloc() der avr-libc hat einen Guard-Bereich gegenüber
dem Stack. Wenn der erreicht wird, verweigert es die Allozierung.
Die Größe kann man als Nutzer festlegen, default ist 32.
Insofern ist es immer noch besser als blindes Allozieren auf dem
Stack, denn da wird nullkommanichts getestet, dass der Stack nicht
in die statisch belegten Daten reinrauscht.
Klar hilft das natürlich nichts, wenn man völlig planlos ist und
nach dem malloc() dann in eine riesig tiefe Rekursion reinrennt …
Jörg W. schrieb:> malloc() gibt sich da> wenigstens noch ein bisschen Mühe, den Überlauf-Fall abzusichern (und> gibt dann 0 zurück).
Und was machst du dann? Die Led "Speicherüberlauf" setzen?
Jörg W. schrieb:> Warum man mit der blöden These, dynamischen Speicher auf Controllern> komplett zu vermeiden, nicht immer weiterkommt
Was ja auch niemand behauptet hat. Wohl aber daß man sie in 9 von 10
Fällen vermeiden kann und dann auch tunlichst soll. Und daß man mit
dynamischer Speicherverwaltung sich ganz schnell Probleme einfängt die
deutlich schwieriger rauszufinden sind wie:
Jörg W. schrieb:> dass einem der Stack dann nicht in die> globalen bzw. statischen Variablen reinrennt
nämlich Speicherleaks und Fragmentierung.
Siehe das Beispiel des TOs. Ziemlich trivialer Code, auch wenn er mit
seinen Variablennamen fast perfektes obfuscating betreibt, und schon 2
Speicherleaks.
Der Andere schrieb:> Jörg W. schrieb:>> malloc() gibt sich da>> wenigstens noch ein bisschen Mühe, den Überlauf-Fall abzusichern (und>> gibt dann 0 zurück).>> Und was machst du dann? Die Led "Speicherüberlauf" setzen?
Das Problem musst du immer behandeln können.
Bei statischer Vorbelegung ist im Zweifelsfalle (wie bei Holm
seinerzeit) deine Ressource "RAM" nämlich schon viel eher alle,
und du kannst eine weiße Flagge zum Fenster raushängen.
Klar: wer solche Probleme gar nicht hat, muss sich daraum auch keine
Gedanken machen. Nicht jeder wird aber in der glücklichen Lage sein,
bereits zur Compilezeit alles zu wissen.
> Und daß man mit> dynamischer Speicherverwaltung sich ganz schnell Probleme einfängt die> deutlich schwieriger rauszufinden sind wie:>> Jörg W. schrieb:>> dass einem der Stack dann nicht in die>> globalen bzw. statischen Variablen reinrennt>> nämlich Speicherleaks und Fragmentierung.
Einfacher? Sorry. Eine durch den Stack zerschossene globale
Variable zu finden, dürfte so ziemlich zu den übelsten Übungen
gehören, die man als Programmierer eines Mikrocontrollers zu lösen
hat. In aller Regel hast du dann, wenn du das Übel bemerkst,
keinerlei Idee mehr, wann das Problem aufgetreten sein könnte.
(Wenn man einen Debugger hat, der Daten-Breakpoints sezten kann,
ist man natürlich klar im Vorteil.)
Dagegen ist eine von malloc() geworfene 0 ja himmlisch einfach zu
debuggen. Auch die Fragmentierung kann man, wenn man es möchte,
gelegentlich verifizieren (zumindest im Debugger), denn bei der
avr-libc ist der Quellcode offengelegt, sodass man sich dessen interne
Datenstrukturen ansehen kann. BTDT.
Fragmentierung ist ohnehin ein eher künstlich aufgebauschtes Problem,
sofern man 1) tatsächlich statistisch gut verteilte Eingabedaten
hat und 2) einigermaßen Reserve beim Speicher. Die nötige Reserve
fällt aber (wiederum: bei Daten mit tatsächlich dynamischer Größe)
immer noch drastisch geringer aus als das, was man benötigt, wenn
man alles in statischen Arrays ablegen möchte. Beispiel: du
bekommst im Laufe der Zeit Anforderungen für 3, 20, 14, 110 und
42 Bytes. Bei statischer Allozierung brauchst du 550 Bytes, um 5
Telegramme von maximal 110 Byte abzulegen. Bei dynamischer Allozierung
brauchst du (auf AVR bezogen) 197 Bytes. Gegenüber den 550 Bytes hast
du jetzt mehr als 100 % Reserve. In dieser Reserve bekommst du auch
für den pathologischen Fall, dass der 110er Block erst als letztes
wieder freigegeben wird, problemlos noch viel mehr Daten unter.
> Siehe das Beispiel des TOs.
Er hat rundum so viele Anfänger-Fehler, die kannst du nun nicht einem
malloc() anlasten.
Das man im Code nicht durchsieht und somit die Gefahr von Leaks sehr
groß ist.
Auch das malloc in dem besagten Code wenig Sinn macht. Zumal dieser
richtig viele Fallen enthält. Ich rate er sich mit dem Thema Pointer und
Strings sich zu beschäftigen.
Auf einen AVR funktioniert der Quark natürlich, ein ARM zieht die
Reißleine. Oder der ESP löst den Schleudersitz aus -> Reset.
Rolf M. schrieb:> Auf dem PC schon, aber auf einem kleinen 8-Bitter nicht.
Die Welt besteht nicht nur aus kleinen 8bittern. Außerdem vermute ich,
dass die malloc Implementierung auf avrs oder Arms nicht nicht gleich
ein paar 10 Bytes benötigt wie auf dem PC.
Rolf M. schrieb:> Wie kommst du darauf? Vom Hörensagen, oder hast du das getestet?
Ich hätte von dir eigentlich was qualifizierteres erwartet. Folgendes
Szenario: es werden fifos unterschiedlicher Größe in einer Klasse
benötigt.
fifo_create(n) gibt ein fifo mit n Elementen zurück.
1
Classfoo{
2
fifo*f;
3
foo(intn){
4
f=fifo_create<int>(n);
5
}
6
}
Ein Template parameter für n führt zu einem weiteren in foo, wodurch für
jede fifogröße neuer Code für foo und fifo angelegt wird. Das einzige
was mir noch einfällt ist, dass man die Funktionalität von foo in einer
Basisklasse implementieren kann. Kleiner und übersichtlicherer wird das
aber sicher auch nicht.
avr schrieb:> Außerdem vermute ich, dass die malloc Implementierung auf avrs oder Arms> nicht nicht gleich ein paar 10 Bytes benötigt wie auf dem PC.ARM benutzt newlib, das könnte schon ein bisschen größer ausfallen.
avr-libc benutzt eine eigene Variante, die hat zwei Byte (ein Zeiger)
Overhead pro Allokation, zuzüglich einiger weniger globaler Variablen.