Hallo, mir sind Begriffe wie aliged, Endian etc und die Zugriffsarten schon bekannt, dass es eben einfacher ist wenn ein uint8_t 32 Bit beansprucht, da der ARM nunmal einen 32 Bit Datenbus hat und 4 Bytes in einem Haps holt, wenn sie an einer / 4 Grenze liegen. In meinem Fall muss ich aber zwingend dafür sorgen, dass uint8_t feld[1024] eben nur 1024 Bytes braucht und nichts mehr. Und das als lokale automatische Var auch nicht auf dem Stack, das muss ins .data segment. Stack ist nur 0x400 gross und es gibt keine Fehlermeldungen wenn der überläuft, nur Abstürze. Zugriffe dürfen kostspieliger sein _attribute((packed)) lässt sich leider nur auf structs und unions anwenden, scheinbar. Wie löse ich mein Problem mit dem GCC, so dass ich auch nachschauen kann was er gemacht hat? Das hier hilft mir auch nicht wirklich weiter: https://www.uninformativ.de/blog/postings/2015-10-25/0/POSTING-de.html Grüße, Christian
Chris J. schrieb: > uint8_t feld[1024] eben nur 1024 Bytes braucht und nichts mehr. Das tut es schon. Da musst du nix mehr dran machen, denn uint8_t hat ein Alignment von 1. Bei gegebener Paranoia kannst du (bei Verwendung von C++) prüfen dass es wirklich nur 1024 Bytes sind:
1 | static_assert(sizeof(feld) == 1024, "Feld hat falsche Groesse!"); |
Chris J. schrieb: > Wie löse ich mein Problem mit dem GCC, so dass ich auch nachschauen kann > was er gemacht hat? Was hast du denn für ein Problem? Es sollte so schon funktionieren.
Chris J. schrieb: > mir sind Begriffe wie aliged, Endian etc und die Zugriffsarten schon > bekannt, dass es eben einfacher ist wenn ein uint8_t 32 Bit beansprucht, > da der ARM nunmal einen 32 Bit Datenbus hat und 4 Bytes in einem Haps > holt, wenn sie an einer / 4 Grenze liegen. In den Registern ja, weil der ARM nur 32-Bit-Register hat. Im Speicher braucht eine 8-Bit-Variable natürlich auch nur 8 Bit. > In meinem Fall muss ich aber zwingend dafür sorgen, dass > > uint8_t feld[1024] eben nur 1024 Bytes braucht und nichts mehr. Das tut es (muss es - das ist in C so vorgeschrieben). > Und das als lokale automatische Var auch nicht auf dem Stack, Lokale automatische Variablen landen immer auf dem Stack oder direkt in Registern (was natürlich bei einem Array dieser Größe nicht geht). > das muss ins .data segment. Dann musst du sie statisch machen und nicht automatisch. > _attribute((packed)) lässt sich leider nur auf structs und unions > anwenden, scheinbar. Weil Arrays per Definition immer gepackt sind. Das Attribut wäre also für Arrays völlig sinnlos. > Wie löse ich mein Problem mit dem GCC, so dass ich auch nachschauen kann > was er gemacht hat? Du kannst dir mit objdump -t (bzw arm-none-eabi-objdump oder wie immer das bei dir heißt) eine Liste aller Symbole anschauen, wo auch die Größe drin steht. Da sollte auch deine Variable zu finden sein, sofern du sie statisch definierst.
Rolf M. schrieb: > In den Registern ja, weil der ARM nur 32-Bit-Register hat. Im Speicher > braucht eine 8-Bit-Variable natürlich auch nur 8 Bit. Ok... nur handelt es sich um internen Speicher. Der ist u.a. auch bitradressierbar. Ist das da dann auch so? Mache ich Wind um nichts? Ich habe nur gemerkt, dass ein struct mit diversen Größen eben nicht genau die Größe hat wie errechnet, sondern etwas größer ist. Das gab Probs als ich einen struct per Funk an an einen 8 Bitter verschickt habe, obwohl ich da auch nur mit uint_xx gearbeitet hatte und nicht mit den üblichen Größen wie int, char etc. Das mit dem Stack geht leider nicht, da bleibt mir wahrscheinlich nur der Heap.... auch wenn der vielleicht etwas altmodisch ist.
Chris J. schrieb: > Ok... nur handelt es sich um internen Speicher. Der ist u.a. auch > bitradressierbar. Bit-Adressierbar auf ARM? Wie das? Meinst du Bit-Banding? Das zählt nicht, da weiß C nix von. Chris J. schrieb: > Ist das da dann auch so? Du meinst den ganz normalen SRAM vom Controller? Dann Ja. Chris J. schrieb: > Mache ich Wind um nichts? Vermutlich. Chris J. schrieb: > Ich > habe nur gemerkt, dass ein struct mit diversen Größen eben nicht genau > die Größe hat wie errechnet, sondern etwas größer ist. Ja, bei structs gibts ggf. Padding-Bytes, damit die Adressen aller Member ein Vielfaches ihres jeweiligen Alignments sind. Chris J. schrieb: > da bleibt mir wahrscheinlich nur > der Heap.... auch wenn der vielleicht etwas altmodisch ist. Altmodisch? Wurde mittlerweile was besseres gefunden? Das Layout eines Datentyps hat nichts mit der Art zu tun, wie es angelegt wird, das ist auf Stack, Heap, globalen Variablen gleich. Interessant wird's höchstens bei lokalen temporären Variablen in Registern. Bei korrektem C Code merkst du da aber überhaupt nichts von. Warum ist das ganze überhaupt wichtig? Ist dein Code vielleicht nicht korrekt? Du hast ein Array, du greifst auf die Elemente zu, C sorgt dafür dass es funktioniert. In welchem Speicher das wie abgelegt wird ist völlig unerheblich. Was ist das eigentliche Problem? Willst du das mit DMA benutzen, direkt über eine Schnittstelle rausschicken o.ä.?
Niklas G. schrieb: > Altmodisch? Wurde mittlerweile was besseres gefunden? Das Layout eines > Datentyps hat nichts mit der Art zu tun, wie es angelegt wird, das ist > auf Stack, Heap, globalen Variablen gleich. Interessant wird's höchstens > bei lokalen temporären Variablen in Registern. Bei korrektem C Code > merkst du da aber überhaupt nichts von. Mein Problem ist, dass ich nur noch 2kb frei habe aber egal welche Größe ich eintrage bei dem array keine Compiler Warnung kommt. Ich habe mich schon mal totgesucht wegen "HardFault Errors" bis ich dann merkte, dass mir der Stack übergelaufen ist, der auf 0x100 stand. Trotzdem danke für die Ausführungen, wieder etwas schlauer geworden. Naja, den heap würde ich allenfalls für binäre Bäume benutzen und damit habe ich auf uC noch nie was zu tun gehabt. Irgendwie geht alles immer ohne diese Haldenspeicher, den ich noch aus den 80igern kenne als ich anfing zu programmieren an der Uni.
Chris J. schrieb: > Mein Problem ist, dass ich nur noch 2kb frei habe aber egal welche Größe > ich eintrage bei dem array keine Compiler Warnung kommt. Klingt komisch. Wird das array überhaupt auf nichttriviale Art genutzt oder wird es vielleicht wegoptimiert?
Chris J. schrieb: > ? Ich > habe nur gemerkt, dass ein struct mit diversen Größen eben nicht genau > die Größe hat wie errechnet, sondern etwas größer ist. Das gab Probs > als ich einen struct per Funk an an einen 8 Bitter verschickt habe, > obwohl ich da auch nur mit uint_xx gearbeitet hatte und nicht mit den > üblichen Größen wie int, char etc. aus dem Grund verschickt man auch keine Structs einfach so. Man baut das Datenpaket "manuell" zusammen.
Chris J. schrieb: > Mache ich Wind um nichts? Ja. Chris J. schrieb: > Ich habe nur gemerkt, dass ein struct Ein struct ist ja aber auch was anderes als ein Array. In einem Array von structs liegen auch alle structs hintereinander, wenn auch die Member im struct selber nicht direkt hintereinander liegen muessen (padding). Chris J. schrieb: > da bleibt mir wahrscheinlich nur > der Heap.... auch wenn der vielleicht etwas altmodisch ist. ??? Chris J. schrieb: > Stack ist nur 0x400 gross und es gibt keine Fehlermeldungen > wenn der überläuft, nur Abstürze. Chris J. schrieb: > Mein Problem ist, dass ich nur noch 2kb frei habe aber egal welche Größe > ich eintrage bei dem array keine Compiler Warnung kommt. Und was hat der Compiler damit zu tun? Der Compiler weiss nicht wie viel Speicher du hast. Chris J. schrieb: > Ich habe mich > schon mal totgesucht wegen "HardFault Errors" bis ich dann merkte, dass > mir der Stack übergelaufen ist, der auf 0x100 stand. Schau mal hier, vielleicht hilft dir das: https://mcuoneclipse.com/2015/08/21/gnu-static-stack-usage-analysis/ https://stackoverflow.com/questions/6387614/how-to-determine-maximum-stack-usage-in-embedded-system-with-gcc Chris J. schrieb: > Naja, den heap würde ich allenfalls für binäre Bäume benutzen und damit > habe ich auf uC noch nie was zu tun gehabt. Irgendwie geht alles immer > ohne diese Haldenspeicher, den ich noch aus den 80igern kenne als ich > anfing zu programmieren an der Uni. Wenn du dynamischen Speicher brauchst, wird der auf dem Heap allokiert. Muss ja auch, weil der Stack ja staendig neu beladen und auch wieder abgeraeumt wird (Funktions ein- und austritt). Und dynamischen Speicher braucht man fuer sehr viel mehr als binary-trees. Wenn du ohne dynamischen Speicher (malloc/calloc/new, free/delete) auskommst ist doch okay. Man kann vieles auch ohne dynamischen Speicher loesen. Auf einem uC ist dynamische Speicher aber mit etwas vorsicht zu geniessen, ggf. muss man sich selbst eine Speicherverwaltung bauen.
Mmh, du hast also Probleme und weisst nicht welche. Und vermutest, dass ein Array irgendwie ein bisschen größer ist als gedacht. Eigentlich 4 Mal so groß, aber sizeof ist zu kompliziert, deshalb fragst Du hier nach einer Lösung. Für ein Problem, dass Du nicht kennst aber das ja da sein könnte.
Chris J. schrieb: > Rolf M. schrieb: >> In den Registern ja, weil der ARM nur 32-Bit-Register hat. Im Speicher >> braucht eine 8-Bit-Variable natürlich auch nur 8 Bit. > > Ok... nur handelt es sich um internen Speicher. Wo der Speicher ist, hat keinen Einfluss auf das Speicherlayout des Compilers. > Ich habe nur gemerkt, dass ein struct mit diversen Größen eben nicht genau > die Größe hat wie errechnet, sondern etwas größer ist. Ja, aber dann waren in deiner Struct die Elemente vermutlich von verschiedenen Typen. In einem Array sind aber alle Elemente vom selben Typ und haben damit die selben Alignment-Anforderungen. > Das mit dem Stack geht leider nicht, da bleibt mir wahrscheinlich nur > der Heap.... Verstehe ich nicht. Warum kann die Variable nicht statisch sein? Das scheint genau das zu sein, was du brauchst. Chris J. schrieb: > Mein Problem ist, dass ich nur noch 2kb frei habe aber egal welche Größe > ich eintrage bei dem array keine Compiler Warnung kommt. Solange das automatisch ist, existiert es zur Compilezeit noch gar nicht, da es erst beim Funktionsaufruf angelegt wird. Es wird bei der Speicherbelegung gar nicht berücksichtigt. Wenn du es dynamisch ("Heap") anlegst, wäre das übrigens auch nicht anders. > Ich habe mich schon mal totgesucht wegen "HardFault Errors" bis ich dann > merkte, dass mir der Stack übergelaufen ist, der auf 0x100 stand. Wie viel Platz für den Stack später zur Laufzeit nötig sein wird, weiß der Compiler ja auch gar nicht. > Naja, den heap würde ich allenfalls für binäre Bäume benutzen und damit > habe ich auf uC noch nie was zu tun gehabt. Irgendwie geht alles immer > ohne diese Haldenspeicher, den ich noch aus den 80igern kenne als ich > anfing zu programmieren an der Uni. Auf dem µC braucht man es auch eher selten, bzw. sollte eher darauf verzichten, wenn möglich. Auf dem PC ist es unverzichtbar. So sehr, dass in manchen Sprachen grundsätzlich alle Objekte dynamisch angelegt werden. Ist also alles andere als "altmodisch".
:
Bearbeitet durch User
Wie oben schon jemand schrieb, die Variable "static" machen.
1 | void f(...) |
2 | {
|
3 | static char x[1024]; // in .data |
4 | ...
|
5 | }
|
6 | |
7 | void g(...) |
8 | {
|
9 | static char y[1024]; // in .data |
10 | ...
|
11 | }
|
12 | void h(...) |
13 | {
|
14 | char z[1024]; // on stack |
15 | ...
|
16 | }
|
Die Variablen x und y belegt dann natürlich dauerhaft den Speicher, je 1024 Bytes - beim wiederholten Aufruf von f/g findet man sogar noch den Inhalt des vorherigen Durchlaufs drin. Wenn du dieses "Feature" nicht brauchst, wäre es sinnvoller, den Stack einfach 1024 Bytes größer zu machen und auto-Variablen (wie z) zu benutzen.
asdfasd schrieb: > Wenn du dieses "Feature" nicht brauchst, wäre es sinnvoller, den Stack > einfach 1024 Bytes größer zu machen und auto-Variablen (wie z) zu > benutzen. Dann steht eben nicht das drin, was man beim letzten mal reingeschrieben hat, sondern irgendwas, was zufällig an dieser Speicherstelle steht.
Kaj G. schrieb: > Und was hat der Compiler damit zu tun? Der Compiler weiss nicht wie viel > Speicher du hast. Aber der Linker weiss es aus dem Linkerfile.... eigentlich muss der alles wissen, auch zur Laufzeit. Das ergibt sich aus der Codeananalyse. In teuren IDEs sieht man auch wieviel Stack man braucht, da die eigene Parser haben in den Editoren. Bei Segger siehste auch ganz genau wieviel welches Modul braucht. Gehen tut das schon. Aber insgesam sind meine Sorgen gelöst, vielen Dank dafür! Auch wenn es nur Hobby ist.. aber eines was mich nie loslassen wird :-)
Chris J. schrieb: > Aber der Linker weiss es aus dem Linkerfile.... eigentlich muss der > alles wissen, auch zur Laufzeit. Zur Laufzeit des Programms? Der Satz ergibt so keinen Sinn! Chris J. schrieb: > Das ergibt sich aus der Codeananalyse. > In teuren IDEs sieht man auch wieviel Stack man braucht, da die eigene > Parser haben in den Editoren. Bei Segger siehste auch ganz genau wieviel > welches Modul braucht. Gehen tut das schon. So, und wie will deine Codeanalyse zum Beispiel bei einer rekursiven Funktion erkennen in welcher Rekursionstiefe die Rekursion (hoffentlich) abbricht? Solche Tools funktionieren immer nur für bestimmte (einfache) Szenarien. Sie ersetzan aber nie Brain 2.0
Chris J. schrieb: > Kaj G. schrieb: >> Und was hat der Compiler damit zu tun? Der Compiler weiss nicht wie viel >> Speicher du hast. > > Aber der Linker weiss es aus dem Linkerfile.... eigentlich muss der > alles wissen, auch zur Laufzeit. Das ergibt sich aus der Codeananalyse. Der Linker macht keine Code-Analyse. > In teuren IDEs sieht man auch wieviel Stack man braucht, da die eigene > Parser haben in den Editoren. Das reicht aber bei weitem nicht, um den Stackverbrauch zu kennen. Im Prinzip müsstest du den kompletten Code ausführen. Allerdings hängt auch dann der Stackverbrauch davon ab, welche Daten man zur Laufzeit reinsteckt. Man muss also erstmal die Inputs kennen, die zu maximalem Stackverbrauch führen.
Chris J. schrieb: > eigentlich muss der > alles wissen, auch zur Laufzeit. Noe, kann er ja nicht wenn die Daten erst zur Laufzeit bekannt werden (z.B. Daten ueber Netzwerk etc.) Wie soll Linker, Compiler, etc. das ausmessen? Das geht nicht. Kein Tool kann wissen, ob da zur Laufzeit 1 Byte oder 10 TB reinkommen. Was ja auch schon gesagt wurde: Rekursion. Mal angenommen du willst die Fakultaet per rekursiver Funktion berechnen. Da macht es schon einen Unterschied ob du !6 oder !42 berechnest. Sind die Argumente aber nicht zur Compilezeit bekannt, kann da auch nichts Analysiert werden. Was ich oben verlinkt habe: Mit dem Compilerflag -fstack-usage bekommst du den statischen Stackverbrauch pro Funktion, daraus kannst du Pi x Daumen grob was zu deinem Stackverbrauch sagen. Chris J. schrieb: > eigentlich muss der alles wissen Eigentlich muss der Programmierer alles wissen und sollte sich gedanken zu seinen Datenstrukturen machen und selbst darauf aufpassen, dass sein Speicher reicht. ;)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.