Guten Morgen,
derzeit bin ich dabei eine verkettete Liste auf einem Mikrocontroller zu
implementieren. Für die Implementierung habe ich folgende Internetseite
gefunden:
https://perlgeek.de/de/artikel/einfach-verkettete-listen
In meiner Anwendung wird dazu zuerst ein Instanz vom Typ node erzeugt
und im Anschluss Speicher mit malloc reserviert. Nun möchte ich zwei
Elemente hinzufügen. Leider funktioniert dies nicht so wie es sein
sollte. Was mache ich hier falsch?
Das ist Dir hier Beitrag "Re: Probleme mit Funktion in C"
von Peter Danegger eigentlich schon gesagt worden.
Vollständiger, compilierbarer Code, der den Fehler zeigt.
Zusätzlich:
Eine Beschreibung inwiefern das tatsächliche Verhalten vom erwarteten
abweicht und in welcher Weise das festgestellt wurde.
Nicht, wenn die Glaskugeln der Leser in einem Thread versagen, einen
neuen aufmachen.
Mahlzeit
Na danke. CopyNPaste-Programmierer, oder?
Die Elemente werden nicht überschrieben. Sofern ich mich darin irre,
fehlte aber immer noch die Angabe darüber auf welche Weise Du das
feststellst.
Du müsstest zunächst einmal C lernen und die Datenstruktur verstehen.
Dann müsstest Du Dir mal darüber klar werden, ob Du nun ein Element
nach einem gegeben oder vor einem gegebenen Element einhängen
willst.
Wir sind doch hier nicht die Hausaufgaben-Mafia. Schalte Dein Hirn
gefälligst ein oder lerne was Anderes.
Du überschreibst ja auch ständig deine Liste. Merk dir nach dem ersten
malloc mal den Anfang mit einer zweiten “node“.
golem schrieb:> node pnode;> pnode = (node)malloc(sizeof(struct list_node));
node list = pnode;
> pnode = insert_right(pnode, 123);> pnode = insert_right(pnode, 345);> pnode = insert_right(pnode, 678);
Dann kannst du die Liste über list durchgehen.
golem schrieb:> derzeit bin ich dabei eine verkettete Liste auf einem Mikrocontroller zu> implementieren.
Hoffentlich nicht für einen ATTiny10...
Ich empfehle Dir, das Programmieren von C und solche Programmierkonzepte
wie verkettete Listen auf auf einem PC zu lernen. Das ist wesentlich
schmerzfreier.
Wenn Du Dich dann einigermaßen sicher fühlst und Deine PC-Programme auf
dem PC korrekt arbeiten, dann wende Deine gelernten Dinge auf die
Programmierung eines µCs an.
Fuer dynamisches Memory benotigt man einen eher dicken controller, sonst
wird das nichts. Zudem braucht man kein dynamisches Memory nur fuer ein
paar Strings.
Was gegen dynamisches Memory spricht : Woher weisst du, dass der
Speicher zur Verfuegung steht ? Was geschieht, wenn er nicht zur
Verfuegung steht ? Was machst du gegen Fragmentierung ? Garbagecollector
? Referencecounting ?
Ich konnte dynamischen Speicher immer vermeiden und bin schon seit 35
Jahren im Geschaeft.
Nop schrieb:> malloc + Mikrocontroller = fail.
Quark, sooo grundsätzlich ist das nicht zutreffend. Malloc bedeutet auch
nicht zwingend, dass wirklich dynamischer Speicher vom Heap angefordert
wird.
Jan K. schrieb:> Quark, sooo grundsätzlich ist das nicht zutreffend. Malloc bedeutet auch> nicht zwingend, dass wirklich dynamischer Speicher vom Heap angefordert> wird.
Es wird bei kleinen µCs meist SRAM statt DRAM sein, aber solltest du
nicht dies gemeint haben: wovon sonst?
A. K. schrieb:> Jan K. schrieb:>> Quark, sooo grundsätzlich ist das nicht zutreffend. Malloc bedeutet auch>> nicht zwingend, dass wirklich dynamischer Speicher vom Heap angefordert>> wird.>> Es wird bei kleinen µCs meist SRAM statt DRAM sein, aber solltest du> nicht dies gemeint haben: wovon sonst?
Kommt drauf an, wie malloc implementiert ist. Is womöglich haarspalterei
und bin mir jetzt beim 2. Lesen nicht mehr sicher, ob das nicht auch ne
Art Heap ist. Aber ich wollte auf einfache malloc Implementationen
hinaus, die nur Adressen von einem großen statischen Array zurückgeben
und die ggf Speicher auch nicht mehr freigeben können, siehe zb die
freertos Implementationen. Aber im Kontext der verketteten Liste macht
das vermutlich auch keinen Sinn.
Ich wollte eigentlich nur sagen, dass malloc nicht grundsätzlich böse
ist auf einem uc. Passt aber möglicherweise nicht gut zum topic,daher
sorry für eventuelle Verwirrung.
Ich hab bei meinem Scheduler einfach die maximale Anzahl von Elementen
schon zur Compilezeit festgelegt.
Das spart sogar etwas RAM, da zur Verkettung der Index des nächsten
Elements reicht (1 Byte).
Beitrag "Wartezeiten effektiv (Scheduler)"
In der Regel weiß man bei einem µC-Programm, welche Menge an Daten
verarbeitet werden müssen. Man kennt die Größe des RAMs, man kennt den
Bedarf und man weiß, dass kein virtueller Speicher zur Vergügung steht.
Daher können in den meisten aller Fälle sämtliche Daten im Speicher
vorher statisch festgelegt werden - wie Peter schon andeutete.
Das Beispiel des TOs - eine verkettete Liste - lässt sich mit einem
simplen statischen Array erschlagen. Wenns aber um das Erlernen des
Umgangs mit solchen verketteten Listen geht, soll der TO einen PC nehmen
und keinen µC. Später, wenns dann läuft, kann er das immer noch auf
einem µC adaptieren... oder doch ganz anders machen, wenn es um eine
konkrete Anwendung geht.
Jan K. schrieb:> Kommt drauf an, wie malloc implementiert ist. Is womöglich haarspalterei> und bin mir jetzt beim 2. Lesen nicht mehr sicher, ob das nicht auch ne> Art Heap ist.
Die Funktion malloc() steht geradezu per Definition für dynamische
Speicherverwaltung per Heap. Ob vom Heap irgendwann einmal Speicher an
ein Betriebssystem zurück gegeben wird, ist irrelevant.
Auf kleinen Mikrocontroller (wie AVR's) sollte man malloc vermeiden,
wann immer es geht. Denn die Speicherverwaltung ist dort nicht so
ausgefuchst, wie man das von aktuellen PC's gewohnt ist.
Früher oder später wirst du dich mit Speicher-Fragmentierung herum
schlagen müssen.
> Früher oder später wirst du dich mit Speicher-Fragmentierung herum
schlagen müssen.
Eher frueher, eigentlich sofort. Dieses Problem faellt nur weg, wenn man
immer die gleiche Groesse anfordert, dann kann man aber gleich ein Array
nehmen.
Hey und die Mikrokontroller heute sind mindestens 8 Mal so schnell wie
mein C64 damals und haben bald die selben Speichergrößen. Da sind so
Pauschaltotschlagargumente wie malloc ist nix für die so langsam
überholt.
>> Auf kleinen Mikrocontroller (wie AVR's) sollte man malloc vermeiden> Die Mikrokontroller heute sind mindestens 8 Mal so schnell> wie mein C64
Der wurde allerdings üblicherweise in Assembler oder Basic programmiert.
Welcher kleine Mikrocontroller (wie AVR's) hat denn 64kB RAM?
fop schrieb:> Hey und die Mikrokontroller heute sind mindestens 8 Mal so schnell wie> mein C64 damals und haben bald die selben Speichergrößen
Ich hab schon Projekte scheitern sehen, die zuviel mit malloc rumgesaut
haben, bei denen war 1MB (!) auf dem Board.
Speicherfragmentierung ist nicht bei 64kB kein Ding mehr. Der
Speicherumfang ist auch egal, entscheidend ist der Adreßraum. Doof nur,
wenn man keine MMU hat und deswegen der Adreßraum mit dem Speicher
identisch ist.
Ein anderer Weg, trotz malloc mit verschieden großen Blöcken keine
Speicherfragmentierung zu haben: man rundet beim Allozieren immer zur
nächsten Zweierpotenz auf. Damit verschwendet man nie mehr als 50%
Speicher.
Nop schrieb:> malloc + Mikrocontroller = fail.
Ähäm...darf ich anmerken das Du hier "fail" bist?
Ich habe das Theater mit den verketteten Listen schon mal durch,
eine Art Protokollkonverter in mitten einer seriellen Strippe mit
Umsortieren der Elemente und deren Anzahl war auch nicht immer gleich..
Verkettete Listen mit malloc() und free() waren der sinnvollste Weg.
Gruß,
Holm
Stefan U. schrieb:> Auf kleinen Mikrocontroller (wie AVR's) sollte man malloc vermeiden,> wann immer es geht. Denn die Speicherverwaltung ist dort nicht so> ausgefuchst, wie man das von aktuellen PC's gewohnt ist.
Frag mal Jörg hier im Forum, (Mod) wir haben damals den malloc() Kram
debuggt).
>> Früher oder später wirst du dich mit Speicher-Fragmentierung herum> schlagen müssen.
Nicht wenn man einen Plan hat was man macht und irgend wann wieder
aufräumt.
Gruß,
Holm
@ Holm Tiffe (holm)
>Ich habe das Theater mit den verketteten Listen schon mal durch,>eine Art Protokollkonverter in mitten einer seriellen Strippe mit>Umsortieren der Elemente und deren Anzahl war auch nicht immer gleich..
Auch das kriegt man mit einem statischen Array hin.
>Verkettete Listen mit malloc() und free() waren der sinnvollste Weg.
Ansichstsache. Dein uC, hier ein AVR, hat nur einen sehr begrenzten
Speicher, und vor allem, die Anwendung ist bekannt und konstant!
Wenn sich da nicht 2 Funktionen gegenseitig um den Speicher streiten,
braucht man da kein malloc(). Und selsbt dann könnte man das einfacher
mittels gegenseitiger Zuweisung/Freigabe von statischen Arrays lösen.
Stefan U. schrieb:> Welcher kleine Mikrocontroller (wie AVR's) hat denn 64kB RAM?
Silabs EFM32GG hat bis 1M Flash und 128kB RAM. Als Cortex-M3 mit maximal
48 MHz ist der noch in der AVR Klasse.
Ein NRF52 von Nordicsemi hat 64 kB RAM (Cortex M4F mit 64MHz + Bluetooth
Low Energy). Ich würde QFN48 noch als klein bezeichnen.
golem schrieb:> derzeit bin ich dabei eine verkettete Liste auf einem Mikrocontroller zu> implementieren.
Und wozu?
Welchen tatsächlichen Sinn soll das haben?
Und warum machst du das nicht aus eigener Überlegung heraus, sondern
sammelst lieber irgendwelches Zeug aus den Untiefen des Internets?
Meinst du, sowas ist auf deinen (nicht genannten) Zweck irgendwie
passend?
Also, eine doppelt verkettete Liste hat auch auf einem µC gelegentlich
ihren Sinn - aber nicht per malloc im RAM, sondern als const... im
Flash. Ich hatte sowas vor Jahren hier im Forum als Menüsystem der
Lernbetty vorgeturnt. Für sowas wie Menüzwecke im µC hat sowas oftmals
seinen Sinn.
Wenn du also wirklich an sowas interessiert bist, dann lade dir die
Lernbetty herunter und studiere dort in der BettyBase die menu.h und
menu.c sowie bettymenu.inc Dateien. Dann reden wir weiter.
W.S.
Falk B. schrieb:> @ Holm Tiffe (holm)>>>Ich habe das Theater mit den verketteten Listen schon mal durch,>>eine Art Protokollkonverter in mitten einer seriellen Strippe mit>>Umsortieren der Elemente und deren Anzahl war auch nicht immer gleich..>> Auch das kriegt man mit einem statischen Array hin.
Aber nicht wenn der Speicher dann voll ist. Ich habe nicht umsonst den
Mega644 verwendet damals.
Verstehe mich richtig, das war ne Auftragsarbeit und die war erfolgreich
und wurde bezahlt.
>>>Verkettete Listen mit malloc() und free() waren der sinnvollste Weg.>> Ansichstsache. Dein uC, hier ein AVR, hat nur einen sehr begrenzten> Speicher, und vor allem, die Anwendung ist bekannt und konstant!> Wenn sich da nicht 2 Funktionen gegenseitig um den Speicher streiten,> braucht man da kein malloc(). Und selsbt dann könnte man das einfacher> mittels gegenseitiger Zuweisung/Freigabe von statischen Arrays lösen.
Du mußt es ja wissen und scheinst von Jörg nicht viel zu halten denn es
war auch seiner Ansicht nach die beste Lösung. Außerdem kennst Du Dich
gut mit der Art Daten aus die ich zu verarbeiten hatte.
Gruß,
Holm
Jim M. schrieb:>> Welcher kleine Mikrocontroller (wie AVR's) hat denn 64kB RAM?> Ich würde QFN48 noch als klein bezeichnen.
Nach dem Motto: malloc darf nur ab QFN64 verwendet werden? ;-)
>> Hier werden die Elemente immer überschrieben. Was müsste ich verändern,> damit immer ein neues Element an das vorhergehendes Element angehängt> wird?
Denk' noch einmal intensiv darüber nach, was Deine Funktion
insert_right() mit den next-Zeigern macht. Was ist der Wert von
list->next, wo zeigt der Zeiger hin? An welches Element Deiner Liste
willst Du new_node anhängen?
@Holm Tiffe (holm)
>> Auch das kriegt man mit einem statischen Array hin.>Aber nicht wenn der Speicher dann voll ist. Ich habe nicht umsonst den>Mega644 verwendet damals.
Deine verketteten Listen sparen aber keinen Speicher.
>Verstehe mich richtig, das war ne Auftragsarbeit und die war erfolgreich>und wurde bezahlt.
Das will ich gar nicht bezweifeln. Jedoch die Aussage, daß es der
sinnvollste Lösungsansatz war. Wenn du ihn noch "alternativlos" nennst,
brennt hier die Luft! ;-)
>Du mußt es ja wissen und scheinst von Jörg nicht viel zu halten denn es>war auch seiner Ansicht nach die beste Lösung.
Das wollte ich in keinster Weise damit ausdrücken. Und da ich das
Problem im Detail nicht kenne, kann ich auch keine harten Aussagen dazu
machen.
Es bleibt aber ein Bauchgefühl übrig.
> Außerdem kennst Du Dich gut mit der Art Daten aus die ich zu verarbeiten hatte.
Nicht wahr? ;-)
Immer locker bleiben, ich will deine Lösung nicht schlecht machen, nur
vor einem drohenden Tunnelblick warnen.
Und gerade bei nur 4kB RAM spricht SEHR viel für ein statisches Array
mit einer Prise Knoff Hoff.
> Deine verketteten Listen sparen aber keinen Speicher.
Das ist der Springende Punkt. Auf einem PC ist es in der Regel gut, wenn
Programme nur so viel Speicher belegen, wie sie tatsächlich auch
benötigen. Denn der Restliche Speicher bleibt für andere Programme frei
und wird vom OS als Cache verwendet.
Aber auf Mikrocontrollern frage ich mich, wie viele Programme da denn
laufen. Normalerweise sicher nur eins. Also darf das Programm gut und
gerne den gesamten freien Speicher belegen (abzüglich Stack).
Mit dynamischer Speicherverwaltung handele ich mir nur unnötigen
Overhead ein.
Stefan U. schrieb:>> Deine verketteten Listen sparen aber keinen Speicher.>> Das ist der Springende Punkt.
Das bezweifle ich.
> Aber auf Mikrocontrollern frage ich mich, wie viele Programme da denn> laufen. Normalerweise sicher nur eins. Also darf das Programm gut und> gerne den gesamten freien Speicher belegen (abzüglich Stack).>> Mit dynamischer Speicherverwaltung handele ich mir nur unnötigen> Overhead ein.
Richtig ist, daß man sich Overhead einhandelt. Ob dieser unnötig ist,
bemißt sich nach dem konkreten Anwendungsfall. Eine dynamische
Speicherallokation hat den Vorteil, daß man den Speicher auch wieder
deallokieren und dann für andere Zwecke verwenden kann. Wenn ich nun
also zwei (oder mehr) Funktionen habe, von denen jede mehr als 50% des
verfügbaren Speichers zu verschiedenen Zeiten und mit verschiedenen
Datenstrukturen nutzen muß, dann ist dynamische Allokation
wahrscheinlich die sinnvollste Lösung.
Ja sicher, aber in diesem Fall sorgt die Programmiersprache automatisch
dafür. Malloc braucht man dazu nicht. Das gilt ja für alle lokalen
Variablen in Funktionen.
@ Stefan Us (stefanus)
>Ja sicher, aber in diesem Fall sorgt die Programmiersprache automatisch>dafür. Malloc braucht man dazu nicht. Das gilt ja für alle lokalen>Variablen in Funktionen.
Das gilt aber nur für lokale, nicht statische Variablen. Es gibt
durchaus Fälle, wo stark schwankende Speichernutzung jenseites eines
Funktionsaufrufs erfolgt. Das kann ggf. mit malloc() besser handhabbar
sein, muss es aber nicht.
Das Ganze erinnert an die Goto-Diskussion ;-)
In deren Verlauf wurden zwar eineige Argumente pro Goto hervorgebracht,
u.a. die überraschend exzessive Nutzung in diversen Linuxkerneln, aber
auch einige abschreckende Beispiele, die ohne Goto mindestens genauso
gut oder sogar deutlich besser waren.
Beitrag "goto verpönt - was dann nehmen?"
Ich versuchs mal so zu formulieren.
Je kleiner der uC/RAM, umso mehr sollte man von malloc() Abstand nehmen
und über eine statische Speicheraufteilung nachdenken.
Falk B. schrieb:> @Holm Tiffe (holm)>>>> Auch das kriegt man mit einem statischen Array hin.>>>Aber nicht wenn der Speicher dann voll ist. Ich habe nicht umsonst den>>Mega644 verwendet damals.>> Deine verketteten Listen sparen aber keinen Speicher.>>>Verstehe mich richtig, das war ne Auftragsarbeit und die war erfolgreich>>und wurde bezahlt.>> Das will ich gar nicht bezweifeln. Jedoch die Aussage, daß es der> sinnvollste Lösungsansatz war. Wenn du ihn noch "alternativlos" nennst,> brennt hier die Luft! ;-)>>>Du mußt es ja wissen und scheinst von Jörg nicht viel zu halten denn es>>war auch seiner Ansicht nach die beste Lösung.>> Das wollte ich in keinster Weise damit ausdrücken. Und da ich das> Problem im Detail nicht kenne, kann ich auch keine harten Aussagen dazu> machen.> Es bleibt aber ein Bauchgefühl übrig.>>> Außerdem kennst Du Dich gut mit der Art Daten aus die ich zu verarbeiten hatte.>> Nicht wahr? ;-)>> Immer locker bleiben, ich will deine Lösung nicht schlecht machen, nur> vor einem drohenden Tunnelblick warnen.> Und gerade bei nur 4kB RAM spricht SEHR viel für ein statisches Array> mit einer Prise Knoff Hoff.
Ich mußte auf einer seriellen Schnittstelle hereinkommende Datensätze
einlesen, zwischenspeichern, danach analysieren und in anderem Format
mit anderer Geschwindigkeit auf einer Anderen wieder ausgeben ..damit
die bestehende EDV mit einem anderen Automaten klar kam.
Die reinkommenden Datensätze bestanden aus verschiedenen Paketen, die
teils nur numerische Daten enthielten aber unter Umständen auch
längliche Kommentarstrings, je nach dem was der analyseautomat so
gemessen hat oder der Bediener zu kommentieren hatte. Es paßte kein
festes Raster auf die Daten, deshalb habe ich die Sätze nacheinander in
eine verkettete Liste einsortiert und zur Auswertung dann die Liste
durchsucht, Werte umgerechnet und anders formatiert den Kladderradatsch
wieder ausgebeben, das Ganze natürlich mit dem jeweiligen von der
Gegenseite erwarteten Handshake.
Ich habe die Liste als Datenbank benutzt und abhängig von Satztyp
Listenelement für Listenelement durchgekämmt. Nachdem der Meßdatensatz
durch war habe ich die Liste im Speicher wieder frei gegeben und ich
habe mit Jörg daran gearbeitet die Fragmetierung zu beseitigen. Da die
Liste nach jedem Datensatz wieder leer war, gabs keine Probleme.
Statische Arrays hätten mich Speicherplatz für Strings gekostet die dann
u.U. kürzer reingekommen sind als als das maximal Mögliche, oder aber
ganz gefehlt hätten. Ein festes Raster hat nicht gepaßt.
Was genau sagtest Du spricht da Alles für ein statisches Array?
Gruß,
Holm
@Holm Tiffe (holm)
>Ich mußte auf einer seriellen Schnittstelle hereinkommende Datensätze>einlesen, zwischenspeichern, danach analysieren und in anderem Format>mit anderer Geschwindigkeit auf einer Anderen wieder ausgeben ..damit>die bestehende EDV mit einem anderen Automaten klar kam.
OK.
>Statische Arrays hätten mich Speicherplatz für Strings gekostet die dann>u.U. kürzer reingekommen sind als als das maximal Mögliche, oder aber>ganz gefehlt hätten. Ein festes Raster hat nicht gepaßt.
OK.
>Was genau sagtest Du spricht da Alles für ein statisches Array?
Die endliche Größe deines sowieso kleinen RAMs und damit die endliche
Anzahl max. speicherbarer Datensätze. Ich hätte es wahrscheinlich mit 1
großen Speicherblock + einem Verwaltungsarray gemacht, in welchem für
jedes gespeicherte Datenpaket die Adresse, Länge, Typ + diveres Infos
(so benötigt) drinstehen. Damit kann man die unterschiedlichen Pakete
lückenlos speichern und irgendwann leicht verarbeiten. Keinerlei
zwingender Grund für malloc(), free() und mögliche Fragmentierung.
Möglicherweise spart das sogar noch einen Tick RAM.
Aber es soll jeder nach seiner Facon glücklich werden.
Falk B. schrieb:>> Die endliche Größe deines sowieso kleinen RAMs und damit die endliche> Anzahl max. speicherbarer Datensätze.
Wie immer war die Aufgabe ursprünglich ganz einfach..danach wurde die
Hardware gebaut. Was folgte war ein moving Target, ich kann mich aber
nicht beschweren, Alles wurde ordentlich bezahlt.
>Ich hätte es wahrscheinlich mit 1> großen Speicherblock + einem Verwaltungsarray gemacht, in welchem für> jedes gespeicherte Datenpaket die Adresse, Länge, Typ + diveres Infos> (so benötigt) drinstehen. Damit kann man die unterschiedlichen Pakete> lückenlos speichern und irgendwann leicht verarbeiten. Keinerlei> zwingender Grund für malloc(), free() und mögliche Fragmentierung.> Möglicherweise spart das sogar noch einen Tick RAM.>
Das was Du hier beschreibst ist eine verkettete Liste bei der die
Pointer vor und zurück in einem Array und nicht in der Liste gespeichert
werden.
Das braucht exakt genau so viel Speicher (Daten + Zeiger bzw Länge),
wobei Du aber einen Teil des verfügbaren Speichers fest im
Inhaltsverzeichnisarray verbrätst, egal wie viele Daten kommen hat
dieses Array immer die selbe Größe und die selbe Anzahl von möglichen
Einträgen und Du hast schlechtere Karten wenn plötzlich wenige Lange
Strings kommen... oder mehr kurze Einträge als Dein Array verwalten
kann.
malloc() und free() bringen immer die Risiko mit das man Bereiche nicht
wieder frei gibt, oder Zeug frei gibt das nicht existiert/schon frei ist
etc.. Memory Leaks. Darüber muß man sich im Klaren sein, allerdings ist
es halt (wie Du gerade siehst) falsch das Zeug von vornherein zu
verteufeln. Auf die Art und Weise wie ich das gemacht habe besteht auch
keine Gefahr das die Fragmentierung für weniger werdenden Speicher
sorgt, weil das Ganze quasi neu initialisiert wurde wenn ein Datensatz
abgehandelt war.
Logischerweise ging das Ganze nicht sofort und hat Arbeit gemacht, aber
es arbeitet heute noch zur Zufriedenheit und hat dazu beigetragen die
malloc Geschichte der AVR-Libc zu debuggen.
> Aber es soll jeder nach seiner Facon glücklich werden.
Freilich doch. Du wußtest es aber von vornherein besser.
Ich werde statischen Speicher verwenden wenn es möglich ist (weil
weniger anstrengend) aber ich habe keine Angst vor "malloc() and
friends" auf Micros.
Gruß,
Holm
@ Holm Tiffe (holm)
>Wie immer war die Aufgabe ursprünglich ganz einfach..danach wurde die>Hardware gebaut. Was folgte war ein moving Target, ich kann mich aber>nicht beschweren, Alles wurde ordentlich bezahlt.
Das ist das Wichtigste ;-)
>Das was Du hier beschreibst ist eine verkettete Liste bei der die>Pointer vor und zurück in einem Array und nicht in der Liste gespeichert>werden.>Das braucht exakt genau so viel Speicher (Daten + Zeiger bzw Länge),>wobei Du aber einen Teil des verfügbaren Speichers fest im>Inhaltsverzeichnisarray verbrätst, egal wie viele Daten kommen hat>dieses Array immer die selbe Größe und die selbe Anzahl von möglichen>Einträgen und Du hast schlechtere Karten wenn plötzlich wenige Lange>Strings kommen... oder mehr kurze Einträge als Dein Array verwalten>kann.
Jain. Real wird es diese Extremfälle nicht so oft geben und selbst wenn,
kann man zu dem Trick greifen, daß man die Pakete vom Speicheranfang
schreibt, die Pointerinfos aber vom Speicherende, so wie es bei Stack
und Heap der Fall ist. Damit hat man maximale Flexibilität ;-)
>malloc() und free() bringen immer die Risiko mit das man Bereiche nicht>wieder frei gibt, oder Zeug frei gibt das nicht existiert/schon frei ist>etc.. Memory Leaks. Darüber muß man sich im Klaren sein, allerdings ist>es halt (wie Du gerade siehst) falsch das Zeug von vornherein zu>verteufeln.
Du missverstehst mich. Ich will es nicht verteufeln, ich will nur für
eher kompakte Anwendungen auf kleinen uCs die Alternative aufzeigen.
Rein sachlicher Wettstreit ohne ideologische Scheuklappen. Das deine
malloc() Version gut funktioniert, will ich gar nicht besteiten.
> Auf die Art und Weise wie ich das gemacht habe besteht auch>keine Gefahr das die Fragmentierung für weniger werdenden Speicher>sorgt, weil das Ganze quasi neu initialisiert wurde wenn ein Datensatz>abgehandelt war.
Also alles freigeben. Ist OK.
>Logischerweise ging das Ganze nicht sofort und hat Arbeit gemacht, aber>es arbeitet heute noch zur Zufriedenheit und hat dazu beigetragen die>malloc Geschichte der AVR-Libc zu debuggen.
Naja, immerhin ;-)
>> Aber es soll jeder nach seiner Facon glücklich werden.>Freilich doch. Du wußtest es aber von vornherein besser.
Nö, aber ich meine, daß immmer mehrere Wege nach ROM führen. Denn es
gibt IMMER Alternativen(!)
>Ich werde statischen Speicher verwenden wenn es möglich ist (weil>weniger anstrengend) aber ich habe keine Angst vor "malloc() and>friends" auf Micros.
Gut.
> Schon interessant, dass jetzt ein Sonderfall dafür steht, dass> man unbedingt überall malloc nutzen muss ;)
Das habe ich anders verstanden. Der beschriebene Sonderfall sollte nur
ein Beispiel sein, wo malloc gerechtfertigt ist.
Schön dass ihr jetzt das leidige Thema malloc auf dem µC mal wieder
durchgekaut habt. Nichts desto Trotz funktioniert sein insert_right wie
erwartet. Sein einziges Problem ist dass er sich seine Liste immer
wieder überschreibt.
Das Problem löst sich, indem (wie ich schon oben angemerkt habe) er sich
den Listenanfang nochmal separat merkt, oder indem er die Zuweisung
weglässt, z.B. so:
Stefan U. schrieb:>> Schon interessant, dass jetzt ein Sonderfall dafür steht, dass>> man unbedingt überall malloc nutzen muss ;)>> Das habe ich anders verstanden. Der beschriebene Sonderfall sollte nur> ein Beispiel sein, wo malloc gerechtfertigt ist.
Mußt Dich nicht wundern, er wollte nur mal nachtreten und erfindet
deswegen wieder Aussagen die Niemand gemacht hat.
Gruß,
Holm
Holm T. schrieb:> Nop schrieb:>> malloc + Mikrocontroller = fail.>> Ähäm...darf ich anmerken das Du hier "fail" bist?
Nein, darfst Du nicht. Du darfst als Bastler aber staunend vom Profi
lernen, daß malloc bei ernsthaften Projekten aus gutem Grund schlichtweg
verboten ist.
Nop schrieb:> Holm T. schrieb:>> Nop schrieb:>>> malloc + Mikrocontroller = fail.>>>> Ähäm...darf ich anmerken das Du hier "fail" bist?>> Nein, darfst Du nicht. Du darfst als Bastler aber staunend vom Profi> lernen, daß malloc bei ernsthaften Projekten aus gutem Grund schlichtweg> verboten ist.
Darf ich das? und der Profi bist Du?
Lachschlapp. Wenn Du weiter gelesen hättest wüßtest Du das ich meine
Brötchen genau damit verdiene und zwar in der eigenen Firma..
Ich würde Dich nicht mal als Türsteher einstellen mit Deiner
Auffassungsgabe. Dein Name hier ist wohl Dein Programm?
Gruß,
Holm
Holm T. schrieb:> Ich mußte auf einer seriellen Schnittstelle hereinkommende Datensätze> einlesen, zwischenspeichern, danach analysieren und in anderem Format> mit anderer Geschwindigkeit auf einer Anderen wieder ausgeben
Ach herrje - und deswegen hast du mit verketten Listen gearbeitet?
Wirklich?
Ich hätte einen passablen Ringpuffer für die Rx-Daten vorgesehen und
einen Stack für die im Stream erkannten Dinge und fertig.
Dein Problem ist ja doch (nach deiner eigenen Schilderung)
input-->Verarbeitung-->Output.
Für so etwas ist eine verkettete Liste schlichtweg das falsche Mittel.
Es kann ja sein, daß ein Umsortieren innerhalb eines oder zweier (oder
dreier) Datenblöcke erforderlich ist, aber dafür eine verkettet Liste?
Sowas benutzt man für Dinge, wo relativ wahlfrei immer wieder auf
Dinge zugegriffen wird, die sich nicht in ein Array fassen lassen, weil
sie eben sowas wie Objekte sind. Ist bei dir aber nicht der Fall, denn
du hast ja nach einem oder zwei Blöcken immer wieder aufgeräumt. Also
ist ein Zugriff auf auseinanderliegende Objekte nicht erforderlich
gewesen. Für sowas macht man einen Stack auf, der quasi unerledigte
Objekte aufnimmt, also einen LiFo-Buffer. Wie gesagt, verkettete Listen
sind dafür, auf verschiedene Dinge IMMER WIEDER zuzugreifen. Für
gleiche Dinge benutzt man besser Arrays.
Aber kommen wir mal zum TO zurück: der hat sich schon ewig nicht mehr
gemeldet, wahrscheinlich hat er gemerkt, daß seine Übung nicht sehr
praxisrelevant gewesen ist.
W.S.
W.S. schrieb:> Holm T. schrieb:>> Ich mußte auf einer seriellen Schnittstelle hereinkommende Datensätze>> einlesen, zwischenspeichern, danach analysieren und in anderem Format>> mit anderer Geschwindigkeit auf einer Anderen wieder ausgeben>> Ach herrje - und deswegen hast du mit verketten Listen gearbeitet?> Wirklich?
Ja wirklich herrje...
>> Ich hätte einen passablen Ringpuffer für die Rx-Daten vorgesehen und> einen Stack für die im Stream erkannten Dinge und fertig.>
Soso, hättest Du... ich übrigens nicht.
Ich dachte eigentlich das Du mir nach der Sache mit dem Lochstreifen
nicht mehr so flach kommst, es sieht aber anders aus. Irgendwie steht
Deine Antwort da noch aus..?
Jeder Abschnitt im Datensatz erforderte ein Handshake nach der
Berechnung der Prüfsumme und ggf. Wiederholung. Zwischenspeichern in
einem Buffer ohne weitere Reaktion war so nicht möglich.
> Dein Problem ist ja doch (nach deiner eigenen Schilderung)> input-->Verarbeitung-->Output.
Nicht ganz..lies nochmal.
>> Für so etwas ist eine verkettete Liste schlichtweg das falsche Mittel.> Es kann ja sein, daß ein Umsortieren innerhalb eines oder zweier (oder> dreier) Datenblöcke erforderlich ist, aber dafür eine verkettet Liste?> Sowas benutzt man für Dinge, wo relativ wahlfrei immer wieder auf> Dinge zugegriffen wird, die sich nicht in ein Array fassen lassen, weil> sie eben sowas wie Objekte sind.
Genau, und das habe ich ja dann auch gemacht.
> Ist bei dir aber nicht der Fall, denn> du hast ja nach einem oder zwei Blöcken immer wieder aufgeräumt.
Sagen wir mal nach 20 oder 30 Blöcken mit dem besonderen Feature das
"Fortsetzungsblöcke" existierten die irgendwann nach anderen Daten
wieder eingeschachtelt wurden.
Der Parser hat dann anhand der Blocktypen in der Liste zur Ausgabe die
Daten wieder zusammengestellt. Durch dieses Konzept war ich bei der
Ausgabe extrem flexibel.
> Also> ist ein Zugriff auf auseinanderliegende Objekte nicht erforderlich> gewesen.
Eben doch, weil bei der Ausgabe u.U. die Daten des ersten und des
letzten Datenblocks eines Datensatzes aufeinander folgend ausgegeben
werden mußten.
Das Lieferformat der Daten war konstant, aber die Ausgabe mußte für
unterschiedliche Anwender (Kunden) angepaßt werden. Der Auftraggeber
lebte davon existierende Geräte bei den Kunden durch seine Eigenen zu
ersetzen und am Vebrauchsmaterial zu verdienen. Daher "moving Target".
> Für sowas macht man einen Stack auf, der quasi unerledigte> Objekte aufnimmt, also einen LiFo-Buffer. Wie gesagt, verkettete Listen> sind dafür, auf verschiedene Dinge IMMER WIEDER zuzugreifen. Für> gleiche Dinge benutzt man besser Arrays.>
Ich weiß das Du es immer besser weißt und wenn man dann das Gegenteil
nachweisen kann wirst Du schlagartig still.
Das Projekt liegt mehrere Jahre zurück, heute hätte ich einen ARM
genommen und hätte viel mehr Speicher zur Verfügung gehabt. Das war
damals so nicht gegeben. Nichts desto trotz hat meine Lösung mit der
Liste als Datenbank für arme Leute bestens funktioniert.
Zusammenfassend sag ichs mal so: "Ach herrje.. wirklich Du jetzt auch
noch?" Du hast mir gerade noch gefehlt...
> Aber kommen wir mal zum TO zurück: der hat sich schon ewig nicht mehr> gemeldet, wahrscheinlich hat er gemerkt, daß seine Übung nicht sehr> praxisrelevant gewesen ist.>> W.S.
Was auch immer. Eventuell ging ihm auch nur auf die Nerven das er statt
einer Lösung immer nur gehört hat das sein Problem gar nicht existieren
darf.
Gruß,
Holm
Nop schrieb im Beitrag #4815588:
> Holm T. schrieb:>> Lachschlapp. Wenn Du weiter gelesen hättest wüßtest Du das ich meine>> Brötchen genau damit verdiene und zwar in der eigenen Firma..>> Du kriegst nichtmal ein einziges Posting hin, ohne ad hominem zu gehen,> und entsprechend fiel die Antwort aus. Im Übrigen würde ich in so einer> Pfuschfirma ohnehin nicht anfangen, danke der Nachfrage. Du hast> offensichtlich keine Erfahrungen mit ernsthaften Projekten, wo Du mit> der postulierten Lösung nichtmal durchs Codereview gekommen wärest.
Ich zitiere mal:
"malloc + Mikrocontroller = fail."
und nochmal "Im Übrigen würde" und "nichtmal durchs Codereview gekommen
wärest"
Also zusammengafaßt: Das ist Deine Idee was eventuell passiert wäre, Du
weißt nichts, hat aber eine vorgefaßte Meinung die wohl auf Deiner
Unkenntnis basiert, dazu kommt "Nop (Gast)" ist auch Niemand.
Du bist "offensichtlich" wichtig wie ein drittes Knie.
Gruß,
Holm
@nop und Andere
Verschwendet nicht eure Zeit, mit dieser hohlm Type kann man nicht
diskutieren.
Vor allem wie der letzte Post wieder ein Paradebeispiel dafür war wie
seine Posts ALLE ad hominem gehen.
Kann da nur aus Erfahrung aus meinem MIPS TTL Thread berichten.
Erstmal wirft er einen irgendwelche Sachen an Kopf ohne sich selber
vorher zu informieren. Wenn man dann Gegenargumente bringt dann werden
diese für ungültig erklärt oder für an den Haaren herbeigezogen erklärt.
Wenn man Ihm dann mit einem Datenblattausschnitt überführt, dass er Mist
schreibt, dann wird er richtig persönlich inkl. Gürtellinien
Unterschreitung.
Zum Thema:
Also ich kenn da genug Firmen wo selbst auf einem größeren ARM Kern mit
16MB+ ext. RAM ein malloc verbot herscht und sogar der Linker Alarm
schlägt falls irgendeine Lib auf die Idee kommen sollte das zu nutzen.
Bei Projekten mit kleinem RTOS drunter wird dann dessen
Speicherverwaltung genutzt. Das sind dann aber meißt mempools, die nur
gleiche BLockgrößen erlauben. Warum gleich groß sollte einleuchten ;)
Mw E. schrieb:> Also ich kenn da genug Firmen wo selbst auf einem größeren ARM Kern mit> 16MB+ ext. RAM ein malloc verbot herscht
Ach herrje. Ich kenne Firmen die kaufen extra einen Controller mit fpu
und verwenden sie dann nicht weil die Softwarefuzzis Angst haben.
Nur weil es viele dämliche Entscheidungen auf dieser Welt gibt muss man
es ja nicht nachmachen...
An alle Kritiker und Zweifler: nennt doch Mal konkrete Probleme mit der
malloc Implementierung der newlib. Mir kommt es so vor als ob alle
bedenkenträger dieser Welt auf dem wissen von vor zwanzig Jahren
herumreiten.
Ich verwende c++ und pure virtuelle klassen auch auf dem Controller.
Objekte werden zum Teil dynamisch erzeugt. Kein Problem damit. Ein paar
Bytes für die sprungtabelle? Drauf ge*##*en.
Mw E. schrieb:> @nop und Andere> Verschwendet nicht eure Zeit, mit dieser hohlm Type kann man nicht> diskutieren.>> Vor allem wie der letzte Post wieder ein Paradebeispiel dafür war wie> seine Posts ALLE ad hominem gehen.
Das kannst Du Dir bitte auch selbst auf die Fahnen schreiben, denn Du
hast damit angefangen. Die Tatsache das Du etwas nicht kannst (mit mir
diskutieren) solltest Du nicht gleich auf die Allgemeinheit
reflektieren. Der Mensch schließt zwar gerne von sich selbst auf Andere,
man sollte aber dann auch ein ausreichendes Maß an Intelligenz
mitbringen um Wahrscheinlichkeiten beurteilen zu können.
>> Kann da nur aus Erfahrung aus meinem MIPS TTL Thread berichten.> Erstmal wirft er einen irgendwelche Sachen an Kopf ohne sich selber> vorher zu informieren. Wenn man dann Gegenargumente bringt dann werden> diese für ungültig erklärt oder für an den Haaren herbeigezogen erklärt.> Wenn man Ihm dann mit einem Datenblattausschnitt überführt, dass er Mist> schreibt, dann wird er richtig persönlich inkl. Gürtellinien> Unterschreitung.>
Du hattest Gegenargumente, ich habe diese entkräftet und Dir Fragen
gestellt. Antwort kam keine, aber das nächste Gegenargument usw..
Du hast mich ständig mit neuen Gegenargumenten, die nicht mal durchdacht
waren beworfen, bist mir aber im Gegenzug jede Antwort auf mein
Nachhaken schuldig geblieben. Du nennst das Diskussionskultur? Ich
nicht.
Du ziehst Dich an 3 TTL Gattern hoch und bietest in Gegenzug ganze
Kuchenbleche voller TTL an..
Es ist ein Unterschied ein Argument "für ungültig zu erklären" wie es
speziell Deine Art ist, oder aber jedes mal Nachweise heraus zu suchen
warum das nicht so ist.. es ging ja sogar so weit das ich
Beschaffungsfragen klären sollte. Im Gegenzug bist Du mir mehr und mehr
blöde gekommen was sich auch in entsprechenden Antworten nieder schlug.
Wenn wir mal von unter der Gürtellinie sprechen: Wofür hältst Du Dein
hinterhältiges Nachtreten in Threads die mit Deinem gar Nichts zu tun
haben? Das ist primitiv mein Lieber.
An Deiner Stelle würde ich mal probieren eine Selbsthilfegruppe der Holm
geschädigten in Leben zu rufen, evtl. kannst Du ja irgendwo
EU-Fördermittel beantragen usw...
>> Zum Thema:> Also ich kenn da genug Firmen wo selbst auf einem größeren ARM Kern mit> 16MB+ ext. RAM ein malloc verbot herscht und sogar der Linker Alarm> schlägt falls irgendeine Lib auf die Idee kommen sollte das zu nutzen.> Bei Projekten mit kleinem RTOS drunter wird dann dessen> Speicherverwaltung genutzt. Das sind dann aber meißt mempools, die nur> gleiche BLockgrößen erlauben. Warum gleich groß sollte einleuchten ;)
So kennst Du solche Firmen? Nenne doch mal ein Beispiel und vor Allem
möchte ich gerne mal einen Linker kennenlernen der sich derart verhält
wie Du es erzählst :-)
Was glaubst Du eigentlich wie ein "kleines RTOS" die Speicherverwaltung
managed? Nicht mit alloca() sondern mit Veilchenduft?
Es ist einfach nur als dümmlich zu betrachten Bibliotheksfunktionen als
böse zu verteufeln nur aus dem Grund das man sie nicht versteht.
Deine Art zu programmieren ist wahrscheinlich der Grund warum heute
Betriebssysteme Gigabytes an Speicher zu verschwenden ohne irgendwie
effizient zu sein.
Wenn Du das Anderswo so gesehen hast, was ich stark bezweifele, dann
solltest Du mal Dein Umfeld ändern.
Gruß und einen schönen 2. Advent,
Holm
Für sowas wurden Linkerscripte erfunden, hier ein Beispiel vom ld:
1
mall = 1 - DEFINED(malloc);
2
ASSERT(mall, "malloc fail")
ASSERT wirft nen Fehler und gibt die Nachricht aus, wenn die Variable 0
ist.
DEFINED gibt 1 zurück wenn das Label definiert ist.
Das kommt dann zurück:
1
mips-elf/bin/ld: malloc fail
2
collect2: Fehler: ld gab 1 als Ende-Status zurück
3
makefile:75: recipe for target 'all' failed
4
make: *** [all] Error 1
Über den Rest diskutier ich mit einem Dogmatiker wie dir nicht, da ich
auch schonwieder absichtliche Falschinterpreationen lese.
Mw E. schrieb:> Für sowas wurden Linkerscripte erfunden, hier ein Beispiel vom ld:>
1
> mall = 1 - DEFINED(malloc);
2
> ASSERT(mall, "malloc fail")
3
>
> ASSERT wirft nen Fehler und gibt die Nachricht aus, wenn die Variable 0> ist.> DEFINED gibt 1 zurück wenn das Label definiert ist.
Oh, Linkerscripte sind mir durchaus vertraut. Un Du kennst Firmen die
sowas da drin stehen haben? Welche?
>> Das kommt dann zurück:>
1
> mips-elf/bin/ld: malloc fail
2
> collect2: Fehler: ld gab 1 als Ende-Status zurück
3
> makefile:75: recipe for target 'all' failed
4
> make: *** [all] Error 1
5
>
>> Über den Rest diskutier ich mit einem Dogmatiker wie dir nicht, da ich> auch schonwieder absichtliche Falschinterpreationen lese.
Das Dogma versuchst u.A. Du doch hier durchzudrücken: Malloc() auf
Mikros ist böse.
Das ist Glaube, und kein Wissen, lt. Wikipedia ist ein Dogmatiker:
"Im Alltagsgebrauch bezeichnet man als Dogmatiker eine Person, die sich
(im Negativen) stur weigert von bestimmten Grundsätzen abzulassen. Der
Begriff beschreibt allerdings Theologen, die sich mit dem Fachgebiet der
Dogmatik befassen."
Es ist Dein Grundsatz mit malloc() von dem Du hier stur nicht abweichen
willst, ergo bist Du der Dogmatiker nicht ich, weil ich keinen solchen
beschränkten Grundsatz durchzudrücken versuche, sondern
malloc(),realloc() und free() nicht als gefährlicher einstufe als andere
Standardfunktionen auch. Bist Du der, der das "Datenblatt" diesmal nicht
gelesen hat?
Falschinterpretationen? Du bist wohl dann zufrieden wenn ich mir von Dir
ans Bein pinkeln lasse und in Ruhe abwarte bis der Stiefel voll ist..ich
versichere Dir: Dieser Fall wird nicht eintreten, mit Verteidigung
meinerseits ist schon vor "voll" zu rechnen.
Wenn Du meine Reaktionen nicht magst, höre einfach auf zu versuchen zu
diskreditieren, dann gibts auch keine Reaktion die Dich schmerzt.
Du müßtest mal versuchen vernünftig und weniger herablassend
aufzutreten, evtl. könntest Du mit mir dann diskutieren auf fachlicher
Ebene und das könnte sogar Beiden Spaß machen, aber nach dem ich Dich
hier 3 Wochen kenne lege ich keinen besonderen Wert mehr darauf mit Dir
zu kommunizieren.
Gruß,
Holm
> ... mir ... Du ... ich ... dir ... ich ... Du ... Dein ... Du ... Du ...> ich ... Du ... Du ... ich mir ... ich ... Dir ... Du ... meine ... Dich> ... Du ... Du ... mir ... ich ... Dich ... ich ... Dir ...
Merkt ihr eigentlich, dass es nicht mehr um "die Sache" geht, wenn in
einem Post arg viele Personalpronomen vorkommen?
Mw E. schrieb:> Vor allem wie der letzte Post wieder ein Paradebeispiel dafür war wie> seine Posts ALLE ad hominem gehen.
Nach meiner Wahrnehmung gingen die ad-hominem-Angriffe von "Nop" aus,
als er Holm als "Bastler" abqualifizierte, der "staunend vom Profi"
lernen dürfe.
Karl schrieb:> An alle Kritiker und Zweifler: nennt doch Mal konkrete Probleme mit der> malloc Implementierung der newlib.
Das haben sie doch schon gemacht: die einen haben Angst davor, die
Freigabe des dynamisch allokierten Speiches zu vergessen, und die
anderen haben Angst vor einer eventuellen Speicherfragmentierung.
Holm T. schrieb:> Das Dogma versuchst u.A. Du doch hier durchzudrücken: Malloc() auf> Mikros ist böse.> Das ist Glaube, und kein Wissen,
Jetzt hast DU (Lothar's_Counter++) aber die Scheuklappe auf.
Nochmal: Man kann vekettete Listen durchaus auch auf einem µC benutzen,
man sollte aber wissen, was man da tut. In den wirklich allermeisten
Fällen erweist sich sowas als herzlich überflüssig, weil fehlgedacht.
Dazu kommt die zumeist anzutreffende Beschränkung in der Hardware, wo
man eben nicht den RAM zur Verfügung hat, um damit lustig per malloc
Platz nach Gusto zu reservieren UND man hat in aller Regel bereits zum
Übersetzungszeitpunkt alle Informationen, die ein malloc überflüssig
machen. Das ist eben eine ganz andere Situation als auf dem PC. Eben
genau deshalb ist malloc und Konsorten auf dem µC suspekt, wer will mag
auch sagen 'böse'.
Der TO hatte einfach nur einige Beispiele hergenommen, die sich eben auf
die Verhältnisse auf dem PC beziehen und wollte damit auf einem µC
starten, ohne wirklich zu verstehen, was das beinhaltet. Das war der
eigentliche Fehler. Siehe:
golem schrieb:> node pnode;> pnode = (node)malloc(sizeof(struct list_node));
Es hat das Reservieren von Speicher wirklich NICHTS mit dem Benutzen von
verketteten Listen zu tun. Das sind verschiedene Dinge -aber soweit muß
man mental erstmal vorankommen!
Und nochwas zu dir, Holm (Lothar's_Counter++):
Holm T. schrieb:> Ich habe die Liste als Datenbank benutzt und abhängig von Satztyp> Listenelement für Listenelement durchgekämmt. Nachdem der Meßdatensatz> durch war habe ich die Liste im Speicher wieder frei gegeben und ich> habe mit Jörg daran gearbeitet die Fragmetierung zu beseitigen. Da die> Liste nach jedem Datensatz wieder leer war, gabs keine Probleme.
Du hast also nicht die Daten beim Hereinkommen bearbeitet, hast sie auch
nicht kompakt gespeichert, sondern als verkettete Liste - und du hast
nach Bearbeitung Probleme gehabt, den Speicher wieder freizukriegen, ja?
Keine weiteren Fragen, Kienzle.
W.S.
Ich hab von nem Kollegen die AVR-ENC28J60-Lib includiert, der benutzt
darin auch malloc. Funktioniert, also mache ich mir da keinen Kopp.
Selber habe ich aber noch keine Applikation gehabt, die von malloc
profitieren würde.
> An alle Kritiker und Zweifler: nennt doch Mal konkrete Probleme mit der> malloc Implementierung der newlib. Mir kommt es so vor als ob alle> bedenkenträger dieser Welt auf dem wissen von vor zwanzig Jahren> herumreiten.
Hallo an alle newlib und malloc Spezialisten, ich verwende auf einen
STM32 die newlib, jetzt ist es so das in cmsis ein unsigned long
pulStack[size] definiert ist.
Der wird aber für den Newlib Heap und den initial Stack verwendet. Der
Newlib Heap wächst von den niedrigen Addressen zu den hohen Addressen
und der Stack von den hohen Addressen zu den niedrigen Addressen.
das der Stack wächst ist für mich ok aber das der Newlib Heap auch
undefiniert wächst ist für mich ein großes Problem eigentlich untragbar
vorallem weil er in großen Sprüngen wächst und das RAM sehr knapp ist
und nicht erörtert werden kann wieviel dafür benötigt wird.
Ich hätte für den Nwelin Heap gerne eine definierte Größe die nicht
überschritten wird, weiß jemand wie das bei Newlib umgesetzt werden
könnte.
Oder habt Ihr auch dieses Problem und wie geht Ihr damit um?
https://en.wikipedia.org/wiki/OSEK
es hat einen Grund warum Firmen kein malloc erlauben, es soll
undefiniertes Verhalten ausgeschlossen werden und das betrifft sehr
viele Bereiche. Wer im Embedded Bereich tätig ist muss wissen wie er
ohne malloc auskommt.
W.S. schrieb:> Holm T. schrieb:>> Das Dogma versuchst u.A. Du doch hier durchzudrücken: Malloc() auf>> Mikros ist böse.>> Das ist Glaube, und kein Wissen,>> Jetzt hast DU (Lothar's_Counter++) aber die Scheuklappe auf.>> Nochmal: Man kann vekettete Listen durchaus auch auf einem µC benutzen,> man sollte aber wissen, was man da tut.
Ja, habe ich gemacht.
> In den wirklich _allermeisten_> Fällen erweist sich sowas als herzlich überflüssig, weil fehlgedacht.>
Es ist ausschließlich Deine Idee zu denken das ich fehlgedacht habe,
denn Dir fehlen die notwendigen Informationen um beurteilen zu können ob
das fehlgedacht war oder nicht.
Würde es Dir viel ausmachen Deine Ideen auf die Vorhersage des Ausgangs
von $Fußballspiel umzulenken, statt auf das was ich vor Jahren
erfolgreich gemacht habe?
> Dazu kommt die zumeist anzutreffende Beschränkung in der Hardware, wo> man eben nicht den RAM zur Verfügung hat, um damit lustig per malloc> Platz nach Gusto zu reservieren UND man hat in aller Regel bereits zum> Übersetzungszeitpunkt alle Informationen, die ein malloc überflüssig> machen. Das ist eben eine ganz andere Situation als auf dem PC. Eben> genau deshalb ist malloc und Konsorten auf dem µC suspekt, wer will mag> auch sagen 'böse'.allermeist, zumeist ... aber eben nicht immer.
Ich habe nirgends behauptet das nun alle Welt ständig dynamishen
Speicher benutzen muß, aber es ist leider völliger Blödsinn das Zeug zu
verteufeln weil man es entweder nicht versteht oder die Impelmentation
buggy ist.
Du kannst übrigens Einen darauf lassen das ich genau wußte was ich wann
und wo wieder freigegeben habe und wie der Fragmentierungszustand des
Speichers aussah nach jeder Operation an der Liste aussah.
Mir ist das gesamte VM System von Windows suspekt weil ich die bessere
Arbeitsweise von dem des FreeBSD Systems kenne, trotzdem gehe ich Dir
nicht mit meinen Ansichten dazu auf die Eier.
>> Der TO hatte einfach nur einige Beispiele hergenommen, die sich eben auf> die Verhältnisse auf dem PC beziehen und wollte damit auf einem µC> starten, ohne wirklich zu verstehen, was das beinhaltet. Das war der> eigentliche Fehler. Siehe:>> golem schrieb:>> node pnode;>> pnode = (node)malloc(sizeof(struct list_node));>> Es hat das Reservieren von Speicher wirklich NICHTS mit dem Benutzen von> verketteten Listen zu tun. Das sind verschiedene Dinge -aber soweit muß> man mental erstmal vorankommen!
Bist Du jetzt auf dem Weg dahin oder was willst Du damit zum Ausdruck
bringen?
>> Und nochwas zu dir, Holm (Lothar's_Counter++):> Holm T. schrieb:>> Ich habe die Liste als Datenbank benutzt und abhängig von Satztyp>> Listenelement für Listenelement durchgekämmt. Nachdem der Meßdatensatz>> durch war habe ich die Liste im Speicher wieder frei gegeben und ich>> habe mit Jörg daran gearbeitet die Fragmetierung zu beseitigen. Da die>> Liste nach jedem Datensatz wieder leer war, gabs keine Probleme.>> Du hast also nicht die Daten beim Hereinkommen bearbeitet, hast sie auch> nicht kompakt gespeichert, sondern als verkettete Liste - und du hast> nach Bearbeitung Probleme gehabt, den Speicher wieder freizukriegen, ja?
Nein.
Wir haben die Bugs aus der malloc() Implementierung von avr-libc
entfernt.
Es ist recht einfach den Speicher wieder frei zu geben wenn man den
Pointer zum ersten Listenelement noch hat, evtl. erzähle ich Dir ja was
Neues...
>> Keine weiteren Fragen, Kienzle.>> W.S.
Keine Antworten mehr für Dich denn: Wieviele Megabyte passen auf eine
Lochstreifenrolle? Hast Du in Deinem Leben schon mal eine gesehen?
Lothars Counter interessiert mich nicht, er kennt meine Meinung dazu.
Gruß,
Holm
Grundsätzlich ist es ja so das solch eine Liste ja keine bestimmte Länge
hat.
Nun kann man statisch Speicher reservieren wie man meint aber am Ende
hängen nur 10 nodes in der Liste.
Dynamisch Speicher zu reservieren und auch diesen wieder Freizugeben ist
gar nicht so unklug.
Sheeva P. schrieb:> Nach meiner Wahrnehmung gingen die ad-hominem-Angriffe von "Nop" aus,> als er Holm als "Bastler" abqualifizierte, der "staunend vom Profi"> lernen dürfe.
Das ist falsch. ICH hatte "mikrocontroller + malloc = fail" geschrieben,
also zur Sache. Holms erstes Posting ging direkt weg von der Sachebene
mit "Ähäm...darf ich anmerken das Du hier "fail" bist?"
Bei seinen Angestellten kann Holm es sich vielleicht leisten, die Leute
direkt persönlich blöd anzumachen (zumindest diejenigen, welche keine
Alternativen haben) - außerhalb davon hat er kein Druckmittel und bekam
von mir entsprechend Antwort. Auch das zählt zu den Sachen, die er noch
lernen kann.
Und seine Idee, ich würde irgendeinen Wert darauf legen, in seiner Bude
anzufangen, zeigt einfach nur groteske Züge.
newlib malloc schrieb:> Der> Newlib Heap wächst von den niedrigen Addressen zu den hohen Addressen> und der Stack von den hohen Addressen zu den niedrigen Addressen.
Das ist ein Design, was von vornherein schon gefährlich ist, weil sie
aufeinander zuwachsen und es bei einer Kollision schlimmstenfalls
nichtmal zu einem Absturz kommt, sondern das System undefiniert
weiterläuft.
Wenn der Speicherverbrauch beidseits stets im grünen Bereich liegt,
kommt es natürlich nicht dazu, aber sicherer ist es, so ein Design von
vornherein zu vermeiden.
Das sollte aber auch eigentlich auch nicht mit der Newlib
zusammenhängen, sondern vielmehr mit dem Linkerscript. Zumindest stelle
ich darüber ein, wo der Stack hingelegt wird.
Siehe auch hier:
http://embeddedgurus.com/state-space/2014/02/are-we-shooting-ourselves-in-the-foot-with-stack-overflow/
Nop schrieb:> newlib malloc schrieb:>> Der>> Newlib Heap wächst von den niedrigen Addressen zu den hohen Addressen>> und der Stack von den hohen Addressen zu den niedrigen Addressen.>> Das ist ein Design, was von vornherein schon gefährlich ist, weil sie> aufeinander zuwachsen und es bei einer Kollision schlimmstenfalls> nichtmal zu einem Absturz kommt, sondern das System undefiniert> weiterläuft.
Das Problem gibt es auch ohne head-Nutzung durch malloc.
Und es lässt sich auch nicht wirklich umgehen, da zur Compilezeit nicht
feststeht, wie intensiv der Stack genutzt wird.
Was machen den die malloc-taboo-Firmen da?
Darf jede Funktion nur einmal aufgerufen werden?
Nop schrieb:> Sheeva P. schrieb:>> Nach meiner Wahrnehmung gingen die ad-hominem-Angriffe von "Nop" aus,>> als er Holm als "Bastler" abqualifizierte, der "staunend vom Profi">> lernen dürfe.>> Das ist falsch. ICH hatte "mikrocontroller + malloc = fail" geschrieben,> also zur Sache. Holms erstes Posting ging direkt weg von der Sachebene> mit "Ähäm...darf ich anmerken das Du hier "fail" bist?">
Und? Was davon hast Du in den falschen Hals bekommen?
Ich habe ein Beispiel dafür angeführt warum das meine Meinung
ist..länglich.
Von Dir kam aber dann nur das Geräusch eines laufenden Föhns..
> Bei seinen Angestellten kann Holm es sich vielleicht leisten, die Leute> direkt persönlich blöd anzumachen (zumindest diejenigen, welche keine> Alternativen haben) - außerhalb davon hat er kein Druckmittel und bekam> von mir entsprechend Antwort. Auch das zählt zu den Sachen, die er noch> lernen kann.
Jetzt hast Dus mir aber gegeben. Ich gehe regelrecht vor Ehrfurcht in
die Knie..Du tapferer Recke.
>> Und seine Idee, ich würde irgendeinen Wert darauf legen, in seiner Bude> anzufangen, zeigt einfach nur groteske Züge.
Beruht ja dann auf Gegenseitigkeit. Du bist ein frech
herumlamentierender "Niemand" der es einem Bastler gezeigt hat. Bravo
Anonymus.
Gruß,
Holm
Nop schrieb:> newlib malloc schrieb:>> Der>> Newlib Heap wächst von den niedrigen Addressen zu den hohen Addressen>> und der Stack von den hohen Addressen zu den niedrigen Addressen.>> Das ist ein Design, was von vornherein schon gefährlich ist, weil sie> aufeinander zuwachsen und es bei einer Kollision schlimmstenfalls> nichtmal zu einem Absturz kommt, sondern das System undefiniert> weiterläuft.>
Quatsch. Das ist eine Frage der konkreten Implementation, Niemand legt
so absolut fest wo der Speicherbereich liegt in dem malloc Speicher
alloziert, den kannst Du auch "nebenan" in einen extra RAM legen, Du
bist doch Herr über den Linker oder?
> Wenn der Speicherverbrauch beidseits stets im grünen Bereich liegt,> kommt es natürlich nicht dazu, aber sicherer ist es, so ein Design von> vornherein zu vermeiden.
Was genau unternimmst Du dann gegen das herunterlaufen des Stackpointers
in Deine statischen Variablenbereiche?
Ist es geradezu gefährlich einen Stackpointer zu verwenden? Keine
Function Calls, kein PUSH, POP und keine Exeptions und INTs mehr aber
dafür sicher?
>> Das sollte aber auch eigentlich auch nicht mit der Newlib> zusammenhängen, sondern vielmehr mit dem Linkerscript. Zumindest stelle> ich darüber ein, wo der Stack hingelegt wird.>
Ach.
[..]
Gruß,
Holm
Sheeva P. schrieb:> Das haben sie doch schon gemacht: die einen haben Angst davor, die> Freigabe des dynamisch allokierten Speiches zu vergessen, und die> anderen haben Angst vor einer eventuellen Speicherfragmentierung.
Na eben nicht. Ersteres ist ein einfacher Bug und Letzteres ist
theoretisch möglich. Die newlib mergt aber auch Blöcke wieder so dass
die Gefahr relativ gering ist.
Natürlich ist es embedded allgemein besser ohne malloc/new auszukommen
aber es gibt auch vernünftige Anwendungen. Wann immer etwas pauschal
verteufelt wird sollten die Alarmglocken schrillen.
Ein Beispiel: Grbl
Alles sehr schön statisch alloziert.
Nimmt man malloc für gcode line buffer sowie TX buffer und planner kann
man den Speicher viel effectiver benutzen und man erspart sich einige
buffer overflow, besonders ärgerlich ist der vom TX buffer.
newlib malloc schrieb:> Ich hätte für den Nwelin Heap gerne eine definierte Größe die nicht> überschritten wird, weiß jemand wie das bei Newlib umgesetzt werden> könnte.
Ja. Das passiert in der Funktion sbrk die du als Low Level Funktion für
die newlib bereitstellen musst. Bei mir gibt es eine heap.c die dir
Funktion und den speicher definiert. Damit kann der Bereich erstens im
linkerscript exakt platziert werden zweitens weiß sbrk wie viel Speicher
Verfügung steht.
Des weiteren liegt mein Main Stack nicht am Ende des Speichers sondern
an Anfang. Wenn er überlaufen sollte gibt es einen Fehler der zu einer
entsprechenden Reaktion führt.
OSEK schrieb:> es hat einen Grund warum Firmen kein malloc erlauben, es soll> undefiniertes Verhalten ausgeschlossen werden und das betrifft sehr> viele Bereiche. Wer im Embedded Bereich tätig ist muss wissen wie er> ohne malloc auskommt.
Hahaha. Erzähl das Mal Toyota. Osek und trotzdem ins Gras gebissen weil
der Stack überlief und als Reaktion einfach der entsprechende Task
angehalten wurde. Dieser ganze Dogmatismus bringt nichts wenn trotzdem
niemand versteht was im Fehlerfall passiert. Trügerische Sicherheit
nenne ich das.
Nop schrieb:
>Das ist ein Design, was von vornherein schon gefährlich ist, weil sie>aufeinander zuwachsen und es bei einer Kollision schlimmstenfalls>nichtmal zu einem Absturz kommt, sondern das System undefiniert>weiterläuft.>Wenn der Speicherverbrauch beidseits stets im grünen Bereich liegt,>kommt es natürlich nicht dazu, aber sicherer ist es, so ein Design von>vornherein zu vermeiden.>Das sollte aber auch eigentlich auch nicht mit der Newlib>zusammenhängen, sondern vielmehr mit dem Linkerscript. Zumindest stelle>ich darüber ein, wo der Stack hingelegt wird.
Es hat damit was zu tun:
#undef errno
extern int errno;
extern int _end;
1
caddr_t _sbrk ( int incr )
2
{
3
static unsigned char *heap = NULL;
4
unsigned char *prev_heap;
5
6
if (heap == NULL) {
7
heap = (unsigned char *)&_end;
8
}
9
prev_heap = heap;
10
11
heap += incr;
12
13
return (caddr_t) prev_heap;
14
}
Diese Funktion wird von Newlib benötigt.
Was mich stört ist das die Größe des Heap nicht definiert ist.
Wie sollte das denn besser gelöst werden?
Karl schrieb:
> Ja. Das passiert in der Funktion sbrk die du als Low Level Funktion für> die newlib bereitstellen musst. Bei mir gibt es eine heap.c die dir> Funktion und den speicher definiert. Damit kann der Bereich erstens im> linkerscript exakt platziert werden zweitens weiß sbrk wie viel Speicher> Verfügung steht.> Des weiteren liegt mein Main Stack nicht am Ende des Speichers sondern> an Anfang. Wenn er überlaufen sollte gibt es einen Fehler der zu einer> entsprechenden Reaktion führt.
Ok, danke. also du hast 2 externe Addressen und nicht nur &_end. Was
machst du wenn über die Größe des Heap darüberhinaus alloziert wird. Man
hat dann zumindest einen genau Aussage das der Heap zu ende ist. Was
soll in diesem Fall die Funktion _sbrk zurückgeben, vermutlich muss
sowieso ein Reset gemacht werden?
Franz schrieb:> Und es lässt sich auch nicht wirklich umgehen, da zur Compilezeit nicht> feststeht, wie intensiv der Stack genutzt wird.
Doch, sicher steht das fest, dafür geht eine worst-case-Stackanalyse.
GCC hilft einem dabei mit -fstack-usage.
Sofern man keine Rekursion verwendet, gibt's dazu sogar Scripte, die aus
den GCC-Daten automatisch den Calltree ermitteln und damit den
Stackverbrauch der Eintrittsfunktion ermitteln. Also bei Singletasking
den von main(), und bei Multitasking den der Taskfunktionen. Keil haut
das praktischerweise sogar gleich automatisch mit raus.
Natürlich müssen Interrupts noch dazu addiert werden, und zwar in der
schlimmstmöglichen Prioritätskette.
Rekursion ist bei ernsthaften Projekten eben deswegen ebenfalls nicht
erlaubt. Sollte man nicht ohne auskommen, muß man die Auswertung manuell
machen, das wird dann halt aufwendiger. Man muß sich dann den
Rekursionspfad anschauen und dessen Verbauch mit N multiplizieren, wenn
man die Rekursionstiefe hart auf N begrenzt (was man tun sollte). Bzw.
mit N+1 multiplizieren, je nachdem, wo und wie man den Begrenzungs-Check
einbaut.
Holm T. schrieb:> Beruht ja dann auf Gegenseitigkeit.
Das kann ich mal so stehenlasssen. Dann haben wir ja geklärt, daß wir
einander nicht ausstehen können, und können uns dann auch wieder der
Technik zuwenden.
Holm T. schrieb:> den kannst Du auch "nebenan" in einen extra RAM legen, Du> bist doch Herr über den Linker oder?
Ich schrieb doch, daß das übers Linkerscript festgelegt wird.
Externes RAM ist allerdings auf STM32 relativ langsam, treibt die BOM
nach oben und schafft zusätzliche Fehlermodi, weswegen es einfacher und
billiger ist, einen größeren Chip zu nehmen, der gleich ausreichend viel
onchip-RAM hat.
Aber, ja klar, wenn man klar diskontinuierliche Adreßbereiche für Stack
und Heap hat, dann ist das zumindest für dieses Problem auch eine
Lösung.
> Was genau unternimmst Du dann gegen das herunterlaufen des Stackpointers> in Deine statischen Variablenbereiche?
Ich lege den Stack nach GANZ unten in seinem Speicherbereich. Die
statischen Variablen liegen dann oberhalb des Stacks. Ein eventueller
Heap wäre dann nochmal darüber.
Stack Overflow (bzw. Unterlaufen beim descending stack des Cortex-M)
rennt damit schlichtweg in einen hard fault und führt somit zum Absturz.
Das ist aber ein klares Fehlerbild, was man loggen kann und sollte.
Zumindest weiß man dann, daß das Gerät noch ein ernsthaftes Problem hat.
Passiert aber nicht, wenn Stackanalyse zur Testphase sowieso in
irgendwelchen Checklisten als verpflichtender Punkt steht und ohne den
entsprechenden Nachweis die SW gar nicht erst freigegeben wird.
newlib schrieb:> Was mich stört ist das die Größe des Heap nicht definiert ist.
Naja an der Stelle, wo der Heapzeiger inkrementiert wird, kann man ja
auch noch einen Check auf die Maximalgröße einbauen. Die Frage ist eher,
was denn die aufrufende Funktion dann tut, und wie man einen Fehler
zurückgibt (wird da ein Nullpointercheck gemacht?).
Und wie die weitere Kette der dann notwendigen Fehlerbehandlung zu
machen ist, denn am Ende steht ja ein gescheitertes malloc, was man
sinnvoll auswerten muß.
Nop schrieb:> Franz schrieb:>> Und es lässt sich auch nicht wirklich umgehen, da zur Compilezeit nicht>> feststeht, wie intensiv der Stack genutzt wird.>> Doch, sicher steht das fest, dafür geht eine worst-case-Stackanalyse.> GCC hilft einem dabei mit -fstack-usage.
Diese Analyse ist für die Nutzung des Heap genauso möglich, es gibt
keinen relevanten Unterschied.
[..]
>> Holm T. schrieb:>> Beruht ja dann auf Gegenseitigkeit.>> Das kann ich mal so stehenlasssen. Dann haben wir ja geklärt, daß wir> einander nicht ausstehen können, und können uns dann auch wieder der> Technik zuwenden.
Auf die Idee hättest Du gerne etwas eher kommen können und den Quark mit
dem Profi stecken lassen.
> Holm T. schrieb:>> den kannst Du auch "nebenan" in einen extra RAM legen, Du>> bist doch Herr über den Linker oder?>> Ich schrieb doch, daß das übers Linkerscript festgelegt wird.
Du schriebst das der Heap in den Stack läuft oder der Stack in den Heap.
>> Externes RAM ist allerdings auf STM32 relativ langsam, treibt die BOM> nach oben und schafft zusätzliche Fehlermodi, weswegen es einfacher und> billiger ist, einen größeren Chip zu nehmen, der gleich ausreichend viel> onchip-RAM hat.>> Aber, ja klar, wenn man klar diskontinuierliche Adreßbereiche für Stack> und Heap hat, dann ist das zumindest für dieses Problem auch eine> Lösung.>>> Was genau unternimmst Du dann gegen das herunterlaufen des Stackpointers>> in Deine statischen Variablenbereiche?>> Ich lege den Stack nach GANZ unten in seinem Speicherbereich. Die> statischen Variablen liegen dann oberhalb des Stacks. Ein eventueller> Heap wäre dann nochmal darüber.
..was bei Überlauf auf STM32 zu einer Exeption führt, und auf dem
Atmega644? Was ist bei der alles ein Micro? Darf der auch eine MMU haben
die Speicherschutz unterstützt?
>> Stack Overflow (bzw. Unterlaufen beim descending stack des Cortex-M)> rennt damit schlichtweg in einen hard fault und führt somit zum Absturz.> Das ist aber ein klares Fehlerbild, was man loggen kann und sollte.> Zumindest weiß man dann, daß das Gerät noch ein ernsthaftes Problem hat.>> Passiert aber nicht, wenn Stackanalyse zur Testphase sowieso in> irgendwelchen Checklisten als verpflichtender Punkt steht und ohne den> entsprechenden Nachweis die SW gar nicht erst freigegeben wird.
Beides sind von Dir angenommenen Voraussetzungen die so keineswegs in
Reallife existieren müssen. Es ist auch nicht so das das verhalten eines
Programms durch die Verwendung von malloc prinzipiell nicht determiniert
wäre.
Fakt bleibt das in beiden Fällen die Kiste oder der Task stecken bleibt
und Mist macht. Why you need a Saddam when you have a Bill? ..oder USS
Yorktown fällt mir dazu ein...
>>> newlib schrieb:>> Was mich stört ist das die Größe des Heap nicht definiert ist.>> Naja an der Stelle, wo der Heapzeiger inkrementiert wird, kann man ja> auch noch einen Check auf die Maximalgröße einbauen. Die Frage ist eher,> was denn die aufrufende Funktion dann tut, und wie man einen Fehler> zurückgibt (wird da ein Nullpointercheck gemacht?).>> Und wie die weitere Kette der dann notwendigen Fehlerbehandlung zu> machen ist, denn am Ende steht ja ein gescheitertes malloc, was man> sinnvoll auswerten muß.
Gehen wir konform mit der Ansicht das es egal ist ob den Index eines
statisches Array über dessen Grenze überläuft oder malloc keinen
Speicher herbeizaubern kann?
Beides sind Fehlerbedingungen die abgefangen werden sollten, weder
dynamischer noch statischer Speicher können das Problem verhindern das
der Speicher simpel alle ist, aber bei dynamischer Allocation habe ich
den Vorteil das anderswo derzeit nicht benötigter Speicher für eine
andere Aufgabe zur Verfügung steht, das ist die Basis jedes VM Systems.
Gruß,
Holm
Holm T. schrieb:> Diese Analyse ist für die Nutzung des Heap genauso möglich, es gibt> keinen relevanten Unterschied.
Sehe ich nicht so, denn wenn das zur Compilezeit bereits ermittelbar
wäre, könnte man das auch gleich statisch machen. Zudem ist ja
keineswegs nur die Nutzung ein Thema, sondern auch noch die
Fragmentierung, vom variablen Timingverhalten eines Allokators mal ganz
zu schweigen.
Ich hatte das auch schon, daß die SW je nach Umständen für
unterschiedliche Sachen recht viel Speicher belegen konnte. Das hab ich
halt in den Stack gesetzt, mit entsprechend fettem Stackverbrauch - aber
durch den Calltree konnte ich ja nachweisen, daß die kritischen
Belegungen nie zugleich auftraten. Fragmentierung und Timing sind dann
kein Thema mehr.
Ansonsten könnte man auch noch z.B. ein statisches char-Array mit
entsprechendem Alignment anlegen, denn char darf alles aliasen.
Natürlich muß man dann sicherstellen, daß es nicht doppelt benutzt wird,
aber das muß man ja so oder so.
> Auf die Idee hättest Du gerne etwas eher kommen können und den Quark mit> dem Profi stecken lassen.
Gerne, wenn Du das "Du bist fail" unterlassen hättest. Sei's drum.
> Du schriebst das der Heap in den Stack läuft oder der Stack in den Heap.
Das war die Frage des Vorposters, bei dem das so war. Mein Kommentar
dazu war dementsprechend, daß man das per Linker anders machen sollte,
mit Verweis zu dem embeddedgurus-Artikel.
Klar, der Vorteil, wenn man sie im selben Speicherbereich aufeinander
zulaufen läßt, ist der, daß man dynamisch mal mehr Stack und weniger
Heap und umgedreht verwenden kann. Ich würde so ein Design aus
grundsätzlichen Erwägungen aber trotzdem nicht machen.
> ..was bei Überlauf auf STM32 zu einer Exeption führt, und auf dem> Atmega644?
Auf dem würde ich mich erstmal ins Datenblatt einlesen, welche
Möglichkeiten man da hat; so ad hoc möchte ich dazu nichts sagen, weil
das ohen Detailkenntnis nicht fundiert wäre. Dennoch, selbst wenn es
keine Exception gibt, ist die Aussicht auf data corruption mit
undefiniertem Verhalten nichts, was ich anstreben würde.
> Was ist bei der alles ein Micro? Darf der auch eine MMU haben> die Speicherschutz unterstützt?STM32 hat keine MMU, sondern nur eine MPU, aber beim Zugriff auf
inexistenten Speicher kommt so oder so eine Exception. Mit MMU sieht die
Fragmentierungsproblematik natürlich schon anders aus, falls der
virtuelle Adreßraum ausreichend groß ist.
> Beides sind von Dir angenommenen Voraussetzungen die so keineswegs in> Reallife existieren müssen.
Ich meinte ja schon, daß ich mit ernsthaften Projekten arbeite, wo
jedenfalls die Analyse fester Teil der Arbeit ist. Klar, wenn man
Consumergeräte hat, ist ohnehin alles egal, weil Verbraucher es
akzeptieren, wenn man das Ding hin und wieder resetten muß.
Industriekunden akzeptieren das aber nicht.
Wenn sowas passiert, hat Sales bei der nächsten Verkaufsrunde ein
Verhandlungsproblem und muß mit dem Preis runtergehen. Auch wenn ich
Festgehalt bekomme, denke ich da über meinen Entwicklungsplatz hinaus an
die Gesamtfinanzen und was ich persönlich dafür tun kann (z.B. mittels
gründlicher Arbeit). Auch dann, wenn es mir nicht durch Checklisten
vorgeschrieben wird.
> Es ist auch nicht so das das verhalten eines> Programms durch die Verwendung von malloc prinzipiell nicht determiniert> wäre.
Es hat schon seinen Grund, wieso das nicht nur in MISRA, sondern auch in
Codingstandards anderweitiger Bereiche mit hohen Anforderungen an die
Zuverlässigkeit nicht erlaubt ist.
Also zumindest nach MISRA darf man das prinzipiell zwar schon, muß dann
aber detailiert nachweisen, daß es nicht zu Problemen führt, was einigen
Aufwand bedeutet - der übrigens bei jedem Release erneut anfällt. Man
muß sich da echt überlegen, welche Wartungskosten man sich ans Bein
binden will.
> Fakt bleibt das in beiden Fällen die Kiste oder der Task stecken bleibt> und Mist macht.
Naja deswegen die Stackanalyse, mit der man nachweist, daß derlei nicht
passiert. Ohne Rekursion ist das auch relativ einfach machbar und sollte
ohnehin zum guten Stil gehören.
Ansonsten sollte man halt irgendeine Art von Fallback-Modus ins Design
planen, was man denn tut, wenn die gewünschte Operation nicht geht. In
Deinem Fall, mit IO-Daten, wäre beispielsweise ein Protokoll denkbar,
was mit verlorenen Daten klarkommt. Oder, wenn es mehr etwas wie
Streaming ist, mit unverändertem Zustand weiterlaufen. Und eine
Regelschleife sollte derlei ohnehin nicht brauchen.
> Gehen wir konform mit der Ansicht das es egal ist ob den Index eines> statisches Array über dessen Grenze überläuft oder malloc keinen> Speicher herbeizaubern kann?
Klar. Wenn man mehr Speicher braucht, als verfügbar ist, hat man immer
ein Problem, egal wo der Speicher herkommt. Aber bei malloc ist das
primäre Problem nicht, daß ein Nullpointer zurückkommen kann.
> aber bei dynamischer Allocation habe ich> den Vorteil das anderswo derzeit nicht benötigter Speicher für eine> andere Aufgabe zur Verfügung steht, das ist die Basis jedes VM Systems.
Nicht nur VM, das ist auch die Basis von PC-Anwendungen - wenn jede
Anwendung alles greift, was sie theoretisch mal brauchen könnte, ist das
Unsinn. Ich schreibe ja hin und wieder auch PC-Tools, und natürlich
nutze ich dann auch malloc usw., und wenn das nicht klappt, beendet sich
das Tool halt mit entsprechendem Fehlercode.
Aber PCs haben eine MMU und spätestens seit x64 einen Adreßraum, der
Fragmentierung zum Nichtproblem werden läßt. Darüberhinaus müssen PCs
üblicherweise auch keine Echtzeitanforderungen erfüllen.
Zudem haben sie einen interaktiven User, was µCs meistens nicht haben.
Die stehen da irgendwo verloren draußen in der Welt und müssen ohne
Hilfe mit einer widrigen Umgebung klarkommen.
Nop schrieb:> Ich meinte ja schon, daß ich mit ernsthaften Projekten arbeite, wo> jedenfalls die Analyse fester Teil der Arbeit ist.
Es gibt eine Welt jenseits von vollzertifiziertgarantierten Programmen,
und dort gelten andere Regeln. Deswegen ist das noch lange keine
Kinderkacke. Deine Weltsicht entspricht in der Hinsicht eher
Scheuklappen.
Mag sein, dass du kein malloc benutzen darfst.
Mag sein, dass du kein printf benutzen darfst.
Mag sein, dass es gute Gründe gegen beides gibt.
Es wird aber immer Fälle geben, wo deren Benutzung anzuraten (oder
zumindest angemessen) ist. Hör bitte einfach auf, dein berufliches
Umfeld als unveränderliche Bibelweisheit anzupreisen.
Holm T. schrieb:> Du bist wohl dann zufrieden wenn ich mir von Dir> ans Bein pinkeln lasse und in Ruhe abwarte bis der Stiefel voll ist
Und du hör bitte einfach mal auf, bei jeder Kleinigkeit verbal in die
Luft zu gehen, bringen tut's ja doch nix. Es reicht völlig aus, fachlich
auf etwas hinzuweisen, deswegen muss man den anderen nicht gleich als
Idioten beschimpfen - egal, ob es stimmt oder nicht.
Dieses ständige Angepisse nervt nämlich. Von beiden Seiten.
Nop schrieb:> In Deinem Fall, mit IO-Daten, wäre beispielsweise ein> Protokoll denkbar, was mit verlorenen Daten klarkommt.
Bei einem reinen Protokollkonverter, wie oben skizziert, darf man davon
ausgehen, dass die Protokolle auf beiden Seiten feststehen. Sonst müsste
man ja nicht konvertieren. Duh.
Doch es geht schon aber er ist eben statisch und verbraucht Ressourcen
die nicht genutzt werden.
Damit die Liste trotzdem nicht unendlich lang wird baut man einen
Counter ein. So hat man die Größe im Blick und kann das Problem vorher
abfangen.
Das Problem mit printf ist das dieses sehr viel Speicher anfordert und
möglich weise den nicht Geschützen Teil überschreibt. Wenn man die
Lebenszeit von Variablen und piontern nicht im Auge hat.
Kurz gesagt wenn man schlecht programmiert kommt es damit zu
unerwarteten verhalten.
Probleme gibt es dann wenn man den Speicher nicht mehr frei gibt oder es
übertreibt. Also zu viel Speicher fest nagelt und dann Funktionen
aufruft die ebenfalls viel Speicher benötigen z.Bsp printf.
Da es beim AVR oder ARM um ein Single Core System handelt kann man
eigentlich immer planen wann was aufgerufen wird.
Man muss sich schon über sein Speicherverbrauch und dessen folgen einig
sein.
S. R. schrieb:
[..]
>> Holm T. schrieb:>> Du bist wohl dann zufrieden wenn ich mir von Dir>> ans Bein pinkeln lasse und in Ruhe abwarte bis der Stiefel voll ist>> Und du hör bitte einfach mal auf, bei jeder Kleinigkeit verbal in die> Luft zu gehen, bringen tut's ja doch nix.
Du wirst damit fertig werden müssen das unser Beider Reizschwellen
offenbar unterschiedliche Größenordnungen haben.
Ich reagiere wenn man mir allzudoof kommt und das bleibt auch so.
>Es reicht völlig aus, fachlich> auf etwas hinzuweisen, deswegen muss man den anderen nicht gleich als> Idioten beschimpfen - egal, ob es stimmt oder nicht.
Mein Firefox meint das das Wort "Idiot" exakt ein einziges Mal in diesem
Thread vor kommt. (jetzt sicher 2 Mal).
>> Dieses ständige Angepisse nervt nämlich. Von beiden Seiten.
Da hast Du schon Recht damit und wenn mich was anpißt dann wehre ich
mich,
das hatte ich doch gerade eben gesagt?
Nop ist in die Luft gegangen als ich schrieb das er mit seiner Meinung
hier "fail" ist ..eine Meinung von mir die Du durchaus zu teilen
scheinst.
Danach habe ich mir angehört das ich unqualifizierter Bastler sei und
später wurde meine Firma hinsichtlich Ihrer Kompetenz durch den Kakao
gezogen. Das sind Sachen die ich so nicht unkommentiert stehen lasse
(..lassen kann, weil geschäftsschädigend), ob es Dir nun paßt oder
nicht.
Hast Du das verstanden?
Nop tritt hier anonym auf und denkt deswegen das er austeilen kann wie
er will ohne sich selbst in Gefahr zu bringen. Für mich gilt das
allerdings nicht.
Gruß,
Holm
Nop schrieb:> Holm T. schrieb:>>>> Auf die Idee hättest Du gerne etwas eher kommen können und den Quark mit>> dem Profi stecken lassen.>> Gerne, wenn Du das "Du bist fail" unterlassen hättest. Sei's drum.
Das hatte keine andere Bedeutung als Deine Meinung für ungültig und
falsch zu deklarieren ..aus genau den Gründen die ich später ziemlich
detailliert auf den Tisch gelegt habe.
Muß ich denn Deiner Meinung sein um zu vermeiden das Du mich als Bastler
der staunend vom Profi lernen darf titulierst und eine 4ma als
Frickelbude (oÄ) bezeichnest..öffentlich?
Für Dich mögen ja Grundsätze gelten an die Du Dich zu halten hat, bei
mir muß das nicht zwangsläufig so sein. Genau deshalb war Deine Aussage
"fail".
>> Du schriebst das der Heap in den Stack läuft oder der Stack in den Heap.>> Das war die Frage des Vorposters, bei dem das so war. Mein Kommentar> dazu war dementsprechend, daß man das per Linker anders machen sollte,> mit Verweis zu dem embeddedgurus-Artikel.
Schön..ist aber auch egal. Du gehst hier von genau 2 Architekturen aus
"PC" bei dem sich die Sache mit VM auch aus Deiner Sicht anders verhält
und STM32..das scheint das zu sein was Du beruflich machst.
Rate mal warum ich gesagt habe Du sollst Micro mal definieren, die
Abwesenheit einer MMU im STM32 hätte eventuell zu dieser Aussage führen
können: "STM32 + komische 'Sicherheitsvorgaben' + malloc +
Mikrocontroller = fail." hat sie aber nicht. Deine Meinung ist einfach
nicht allgemeingültig.
[..]
>>> ..was bei Überlauf auf STM32 zu einer Exeption führt, und auf dem>> Atmega644?>> Auf dem würde ich mich erstmal ins Datenblatt einlesen, welche> Möglichkeiten man da hat; so ad hoc möchte ich dazu nichts sagen, weil> das ohen Detailkenntnis nicht fundiert wäre.
Kurz: gar Keine. Der Pointer wrapt einfach.
> Dennoch, selbst wenn es> keine Exception gibt, ist die Aussicht auf data corruption mit> undefiniertem Verhalten nichts, was ich anstreben würde.
Es gibt keine data corruption, die Mühle hört einfach auf dem Automaten
seine Daten abzukaufen wenn die Kapazitätsgrenze erreicht ist weil die
Liste zu lang wird.
>>> Was ist bei der alles ein Micro? Darf der auch eine MMU haben>> die Speicherschutz unterstützt?>> STM32 hat keine MMU, sondern nur eine MPU, aber beim Zugriff auf> inexistenten Speicher kommt so oder so eine Exception. Mit MMU sieht die> Fragmentierungsproblematik natürlich schon anders aus, falls der> virtuelle Adreßraum ausreichend groß ist.
Schrieb schon, der Grund der Nachfrage war ein Anderer, ich kenne einige
STM32.
>>> Beides sind von Dir angenommenen Voraussetzungen die so keineswegs in>> Reallife existieren müssen.>> Ich meinte ja schon, daß ich mit ernsthaften Projekten arbeite,
Mein Gott!
Ich habe doch nirgends geschrieben das Du dummes Zeug machst (war bei
Dir aber anders) nur Deine Vorgaben ziehen nicht überall und sind
deshalb aus unterschiedlichen Gründen nicht allgmeingültig.
> wo> jedenfalls die Analyse fester Teil der Arbeit ist. Klar, wenn man> Consumergeräte hat, ist ohnehin alles egal, weil Verbraucher es> akzeptieren, wenn man das Ding hin und wieder resetten muß.> Industriekunden akzeptieren das aber nicht.>
Ehy Du ...es war kein Privatkunde der diese Mimik bei mir bestellt hat.
> Wenn sowas passiert, hat Sales bei der nächsten Verkaufsrunde ein
Sales bin auch ich.
[..]
> Es hat schon seinen Grund, wieso das nicht nur in MISRA, sondern auch in> Codingstandards anderweitiger Bereiche mit hohen Anforderungen an die> Zuverlässigkeit nicht erlaubt ist.
Ja, Engstirnigkeit und Unwissen derer die die Standards schreiben.
Du glaubst nicht was es für idiotische Standards gibt und das nicht nur
für Programmierstandards.
>> Also zumindest nach MISRA darf man das prinzipiell zwar schon, muß dann> aber detailiert nachweisen
[..]
>> Zudem haben sie einen interaktiven User, was µCs meistens nicht haben.> Die stehen da irgendwo verloren draußen in der Welt und müssen ohne> Hilfe mit einer widrigen Umgebung klarkommen.
Ich sitze hier vor einem PC der auch mit 100 interaktiven Nutzern kein
Problem hat und ich habe "headless" Server in Rechenzentren stehen.
Du guckst scheinbar durch einen schmalen Tunnel..
Gruß,
Holm
@Holm & @Nop:
Ich bitte Euch, mal tief durchzuatmen und persönlich bezogene
Bemerkungen zu unterlassen. Man kann durchaus auch ohne Anfeindungen
diskutieren.
Sollte hier nichts mehr zum eigentlichen Thema kommen, werde ich den
Thread schließen.
Frank M. schrieb:> Sollte hier nichts mehr zum eigentlichen Thema kommen, werde ich den> Thread schließen.
Es kam nichts...
Wenn jemand meint, er hätte noch was Sachliches, was unbedingt
geschrieben werden müsste, dann bitte eine PN an mich.