Mir ist gerade etwas interessantes aufgefallen das ich mal zur Diskussion stellen wollte. Mein Compiler: gcc-Version 4.7.4 (GCC) Controller: GiantGecko StartupCode: startup_efm32gg.S Wir alle verwenden globale Variablen ja selten. Aber gelegentlich kommt es ja mal vor das dies sinnvoll ist. Und noch seltener kommt es vor das es sinnvoll sein kann das eine Variable beim start einen bestimmten Wert hat. Ich habe hier folgendes Programmiert: #define SYSTEMREADY 4711 #define SYSTEMSTOP 0 volatile static int resetval=SYSTEMSTOP; Das fuehrte zu folgendem interessanten verhalten. Mein Programm funktioniert beim einschalten des Microcontrollers, aber nach einem Reset oder beim flashen ueber den Debuger nicht mehr weil der Startupcode die Variablen nicht initialisiert. Das entsprach schon mal so gar nicht meiner Erwartung, was aber wohl daran lag das ich bisher meine Startcodes immer selber geschrieben habe. Also mal kurz den Code gelesen. In der Tat es gibt da ein Define. nimmt man das in seine CFLAGS auf "-D__NO_SYSTEM_INIT=1" so wird initialisiert. Allerdings mit einer interessanten Ausnahme. Initialisiert man mit 0 wie oben wird immer noch nicht initialisiert. Erst wenn man es so macht: #define SYSTEMREADY 4711 #define SYSTEMSTOP 0xdead volatile static int resetval=SYSTEMSTOP; ..bekommt man das erwartete Verhalten. Hab ich diese charmante Eigenschaft in den letzten 30Jahren C-Programmierung uebersehen? Oder ist das eine spezielle Eigenart von ARM oder Silabs? Haettet ihr das gewusst? :-) Olaf
Also mit 0 ist der Wert beim Start ungleich 0?... Bist Du sicher? Oder kennst Du den Unterschied nicht?
olaf schrieb: > Wir alle verwenden globale Variablen ja selten. Aber gelegentlich kommt > es ja mal vor das dies sinnvoll ist. > ... > Ich habe hier folgendes Programmiert:... Aha. Wohl jeder von uns verwendet gelegentlich globale Variablen. Sowas ist schlichtweg die Normalität - und du brauchst dich dafür nicht verschämt zu verstecken. Aber was du da ("hier") an "Folgendem" programmiert hast, ist zumindest mir unverständlich. Wo finden denn deine zwei Zahlen 0 und 4711 tatsächlich eine Verwendung? Ansonsten krieg ich bei sowas: "volatile static int resetval=SYSTEMSTOP;" regelmäßig nen dicken Hals. Mein wirklich ernstgemeinter Rat ist: Erstens: Dir den tatsächlich in Verwendung befindlichen Startupcode mal kritisch anzuschauen. Zweitens: Dich nie und nimmer auf als selbstverständlich angenommene Initialisierungen zu verlassen und deine Variablen vor ihrer Verwendung dediziert selbst zu initialisieren. Das gilt sowohl für globale als auch für lokale Variablen. Den immer am den Spruch von Max (Sam&Max): "ich traue ihm nur soweit, wie ich ihn selber schmeißen kann". Das gilt für alle Variablen gleichermaßen. Drittens: Das Wort "static" zu vermeiden - egal wo. Viertens: Immer Deklarationen und Belegungen zu trennen. Also nicht wie oben schreiben, sondern sinngemäß so:
1 | extern volatile int IrgendwasIrgendwo; |
2 | ...
|
3 | IrgendwasIrgendwo = 47110815; |
W.S.
Hört sich an, als würde der Startup-Code das .BSS Segment nicht nullen, in denen der Compiler nichtinitialisierte globale Variablen (und explizit auf Null gesetzte) unterbringt.
:
Bearbeitet durch User
Mit Verlaub, Du hast schon eine seltsame Art, Fragen zu stellen. Vielleicht bin ich ja zu blöd, aber ich musste deinen Text tatsächlich mehrmals lesen, bis ich verstanden habe, worum's dir eigentlich geht. Aber erstmal die Antwort auf deine Frage: ja, hätten wir gewusst. Und dann dazu, was Du (glaube ich zumindest) meinst: Der Startup-Code gehört mit zum Programm. Und egal, ob man den selber schreibt, sich irgendwo zusammenklaut oder was Fertiges benutzt, man sollte in jedem Fall wenigstens halbwegs wissen, was er macht. Anscheinend wollte der Schreiber deines Startup-Codes zwischen Kaltstart und Reset unterschieden haben. Kann man machen, muss man aber nicht. Das Minimum, was der Startup-Code machen muss, ist das .data-Segment ins RAM kopieren und das .bss-Segment löschen. Der Compiler steckt alles was != 0 initialisiert wird, ins .data-Segment, im .bss-Segment landet der Rest (es sei denn, Du hast zusätzlich noch eigene Segmente). Das ist eigentlich schon alles, was Du wissen musst, um das Verhalten zu verstehen.
W.S. schrieb: > Drittens: > Das Wort "static" zu vermeiden - egal wo. > > Viertens: > Immer Deklarationen und Belegungen zu trennen. Also nicht wie oben > schreiben, sondern sinngemäß so:extern volatile int IrgendwasIrgendwo; > ... > IrgendwasIrgendwo = 47110815; Erstens und zweitens würde ich noch durchgehen lassen, aber drittens und viertens ist Quatsch. static verwendet man genau dort (wie alle anderen Sprachelemente von C auch), wo es sinnvoll ist. Das geht natürlich nur (aber das gilt wiederum nicht nur für C, sondern auch für alle anderen Programmiersprachen und überhaupt alle Werkzeuge im Universum), wenn man auch verstanden hat, wozu es gut ist und wie man damit umgeht. Deklaration und Initialisierung trennt nur der dogmatisch, der seinem Startup-Code nicht traut.
> Das Minimum, was der Startup-Code machen muss, ist das .data-Segment ins > RAM kopieren und das .bss-Segment löschen. Das ist ja genau der Punkt. Der Startcode kopiert das .data Segment per default nicht, aber es laesst sich einschalten. Das kann natuerlich beabsichtigt sein. Compiler legt aber Variablen die man mit 0 initialisiert hat ins bss Segment, was auch noch eine gewisse Logic hat, spart es doch etwas Flash, aber die loescht er dann nicht. Vielleicht gibt es da auch noch ein eigenes define fuer. Muss ich nochmal genauer schauen. Aber es stimmt schon, am besten ist es man kuemmert sich um alles selber. Olaf
olaf schrieb: > Ich habe hier folgendes Programmiert: > > #define SYSTEMREADY 4711 > #define SYSTEMSTOP 0 > volatile static int resetval=SYSTEMSTOP; > > Das fuehrte zu folgendem interessanten verhalten. Mein Programm > funktioniert beim einschalten des Microcontrollers, aber nach einem > Reset oder beim flashen ueber den Debuger nicht mehr weil der > Startupcode die Variablen nicht initialisiert. Dann ist es ein Bug im Startup-Code oder dieser spielt nicht richtig mit dem Linker-Script zusammen. Schau dir die verfügbaren Infos an: Wo und wie legt der Compiler das Datum ab (abhäbgig von Compiler-Optionen und Code in: common, .bss, .data oder wegoptimiert), was sagt das Map-File, welche Symbole definiert das ld-Script und wie werden diese vom Start-Code verwendet, etc. > Das entsprach schon mal so gar nicht meiner Erwartung, was aber wohl > daran lag das ich bisher meine Startcodes immer selber geschrieben habe. Aha. > In der Tat es gibt da ein Define. nimmt man das in seine > CFLAGS auf "-D__NO_SYSTEM_INIT=1" so wird initialisiert. Und wo wirkt das? Als Makro im Quelltext? Als Makro in einem präprozessiertes Linker-Sktipt? Als Makro im Startup-Code? > Initialisiert man mit 0 wie oben wird immer noch nicht initialisiert. Eruier erst mal, wo das Objekt landet. Datenablage ist anhängig von Compiler-Optimierung und LTO sowie von: -f[no-]data-sections, -f[no-]common, -f[no-]zero-initialized-in-bss, etc. > Erst wenn man es so macht: > > #define SYSTEMSTOP 0xdead > volatile static int resetval=SYSTEMSTOP; > > ...bekommt man das erwartete Verhalten. Vermutlich ein Bug im Start-Code, wo nur .bss genullt wird, nicht aber COMMON, oder COMMON fehlt im Linker-Skript und die Orphan-Platzierung ist anders als erwartet. Ohne mehr Info kann man aber nur raten. > Hab ich diese charmante Eigenschaft in den letzten 30Jahren > C-Programmierung uebersehen? Sieht man nur bei falschen Start-Code, falschem Linker-Script oder nicht-konformen Tools :-) W.S. schrieb: > Zweitens: > Dich nie und nimmer auf als selbstverständlich angenommene > Initialisierungen zu verlassen und deine Variablen vor ihrer > Verwendung dediziert selbst zu initialisieren. In dieser Allgemeinheit ist die Aussage für globale Variablen einfach Käse. > "ich traue ihm nur soweit, wie ich ihn selber schmeißen kann". > Das gilt für alle Variablen gleichermaßen. Und warum verwendest du dann überhaupt Compiler? Wenn die sich eh an keinen Standard halten, lass einfach deine Finger davon und nimm was Vernünfiges. > Drittens: > Das Wort "static" zu vermeiden - egal wo. So ein Unsinn. Dass du keine Ahnung hast, was static in C bedeutet, hast du in Beitrag "C Anfängerfrage (static innerhalb einer Funktion)" ja prächtig demonstriert. Nicht weiter erwähnenswert, wenn du dazu lernen würdest — was offenbar nicht der Fall ist (und stattdessen posaunst auch noch noch damit rum).
Beim Code Composer Studio von TI hatte ich auch die nette Überraschung, daß das .bss Segment NICHT automatisch gelöscht wurde. Das steht auch so im Compilerhandbuch, daß man das im Startup-Code selber machen muss. Ich hab dann was passendes im TI-Forum gefunden und eingebaut. Seitdem ist das Ganze wieder C-Standard konform. Aber verwirrend war das schon, vor allem weil alle Beispiele von TI mit dem Würg-Around der manuellen Initialisierung ALLER Variablen arbeiten . . .
W.S. schrieb: > Drittens: > Das Wort "static" zu vermeiden - egal wo. Nachdem Du kürzlich so gründlich dargelegt hast, daß Du nicht verstehst, wozu es da ist, kann ich diesen Ratschlag nachvollziehen.
> Dann ist es ein Bug im Startup-Code oder dieser spielt nicht richtig mit > dem Linker-Script zusammen. Im oben der oben von mir angefuehrten Startupdatei gibt es ganz einfach keinen code der bss loescht. Das ist wohl auch schon anderen mal aufgefallen: http://www.keil.com/support/docs/2821.htm > Und wo wirkt das? Hier mal ein ausschnitt aus der startup Datei: Reset_Handler: #ifndef __NO_SYSTEM_INIT ldr r0, =SystemInit blx r0 #endif ldr r1, =__etext ldr r2, =__data_start__ ldr r3, =__data_end__ subs r3, r2 ble .flash_to_ram_loop_end .flash_to_ram_loop: subs r3, #4 ldr r0, [r1, r3] str r0, [r2, r3] bgt .flash_to_ram_loop .flash_to_ram_loop_end: ldr r0, =main Ich hab da gerade noch folgendes eingebaut: # Clear .bss section (Zero init) mov r0, #0 ldr r2, =__bss_start__ ldr r3, =__bss_end__ subs r3, r2 ble .zero_to_bss_loop_end .zero_to_bss_loop: subs r3, #4 str r0, [r2, r3] bgt .zero_to_bss_loop .zero_to_bss_loop_end: Aechz..das erstemal seit >10J mal wieder Assembler programmiert. :-) Jetzt sieht aber alles gut aus. Olaf
W.S. schrieb: > Dich nie und nimmer auf als selbstverständlich angenommene > Initialisierungen zu verlassen und deine Variablen vor ihrer Verwendung > dediziert selbst zu initialisieren. Das ist Unsinn, weil der Compiler sich beim Optimieren darauf verlassen darf, daß ein Startupcode existiert, der globale Variablen standardkonform initialisiert. Sprich, solche expliziten Null-Initialisierungen darf er einfach wegoptimieren. Und dann steht man so richtig im Regen, weil man irrtümlich denkt, man hätte es richtig gemacht. Deswegen ist die von Dir vorgeschlagene Lösung schlichtweg grober Pfusch. Wegen genau solcher möglichen Probleme im Startupcode schreibt man den auch am besten selber, denn dann weiß man, daß es richtig gemacht ist. Ist jetzt ja auch kein Hexenwerk mit den Importen aus dem Linkerscript. Außerdem verwendet man selbstverständlich static bei globalen Variablen, weil das zumindest mal den Scope begrenzt.
Nop schrieb: > Sprich, solche expliziten Null-Initialisierungen darf er einfach > wegoptimieren. (Nachtrag: in dem Fall nicht, wegen volatile, aber das macht die Pfuschlösung nicht besser.)
olaf schrieb: > Johann L. schrieb: >> Dann ist es ein Bug im Startup-Code oder dieser spielt nicht richtig mit >> dem Linker-Script zusammen. > > Im oben der oben von mir angefuehrten Startupdatei gibt es ganz einfach > keinen code der bss loescht. Der Startup-Code scheint ja zur Anwendung zu gehören, zumindest wird er mit dieser zusammen Compiliert / Assembliert. Dann muss also der Anwender wissen, was er tut. Wenn das Device wirklich sooo winzig ist, dass die paar Bytes zum Initialisieren von .bss eine Rolle spielen, dann gibt es bessere Ansätze, welche die Tools wählen können: * Über Schalter kann der Start-Code ausgelassen bzw. nicht gegen diesen gelinkt werden, z.B. -nocrt0, -nostartfiles, etc. wenn eigener Code stattdessen verwendet wird. * Es gibt spezielle, vordefinierte, leere weak-Funktionen, die der Startup-Code aufruft, und die von der Anwendung "überschrieben" werden können um eigene Initialisierungen zu erledingen, etwa __init oder ___main. * Es gibt spezielle Sections, über welche Startup-Code hinzugefügt werden kann, z.B. .initN oder __attribute((constructor)). * Zur Initialisierung von .bss und .data wählt avr-gcc folgenden Ansatz: Es gibt 2 unanhängige Routinen in der libgcc, die diese Aufgaben übernehmen, aber ohne sie zu referenzieren wird dieser Code natürlich nicht verwendet. Die Referenzierung erledigt der Compiler: er weiß für jedes Modul, ob es eine Initialisierung von .bss oder .data triggert und linkt dann gegen den entsprechenden Code. Wenn .bss nicht verwendet wird, dann wird der Code zum 0-en von .bss auch nicht gelinkt. * Soll Code im Static Storage nicht initialisiert werden (z.B. weil er einen Warmstart überleben soll) dann gibt es z.B. __attribute((section(".noinit"))). Beispiel sieht man in den Linker-Scripts für avr-gcc; eine Behandlung in Compiler oder Linker ist nicht notwendig. Prinzipiell kann man diesen Init-Teil des CRT auch weglassen und muss sich dann selber überlegen, wie man die dann nicht mehr konforme C-Implementation konform macht. Oder wie man um die Nichtkonformität herum hackt. Das Herum-Hacken mittels händischer Belegung hat folgende entscheidende Nachteile: * Es gibt keinen kanonischen Ort dafür, etwa für Module-static oder Function-static. Diese Variablen sind nicht von main aus erreichbar, und um sich zu merken, ob diese Variablen bereits initialisiert sind, bräuchte man weitere Variablen, um sich den Zustand "Initialisiert oder nicht" zu merken. * Selbst wenn man auf static verzichtet, führt dies zu unliebsamen Querabhängigkeiten zwischen den Objekten und dem Code, der diese initialisiert; man muss ständig darum bedacht sein, beide Codestellen konsisitent zu halten. * Hat man nur sehr wenige Objekte und kleinen Code, kann eine händlische Initialisierung zu ein paar Byte kleinerem Code führen — falls es wirklich eine Rolle spielen sollte, das letzte Byte an Codegröße rauszuquetschen. I.d.R. wird der Code aber deutlich größer und schlechter wartbar. * const ist nicht mehr verwendbar, da const nicht vom der Anwendung geschrieben werden kann (und wenn doch, dann ist es Undefined Behaviour). * In C++ ist const eine echte Obermenge von read-only. Der Compiler kann einen artifiziellen, statischen Constructor zur Initialisierung dieser Objekte erstellen und ein const zur Laufzeit schreiben. Wird dieser Code nicht ausgeführt (weil Start-Code nicht dazu passt), ist das komplette Programm dysfunktional.
Nop schrieb: > Das ist Unsinn, weil der Compiler sich beim Optimieren darauf verlassen > darf, daß ein Startupcode existiert, der globale Variablen > standardkonform initialisiert. Du bist jetzt schon der gefühlt 100ste, der nix anderes antworten kann als "Unsinn". Nein, es ist wirklich kein Unsinn, sondern nur von dir und all den anderen nicht verstandener Sinn. Sozusagen das ständige Repetieren auswendig gelernter Leitsätze. Ich habe ja garnichts gegen Leitsätze - aber das Leben ist anders, siehe unten. Mir ist wirklich kein C-Compiler bekannt, der selbst bei ausgiebigster Optimierung ganze Anweisungen, mit denen einer Variable ein Wert (0 oder sonstwas) zugewiesen wird, einfach wegläßt. Selbst der knöselige GCC macht sowas nicht. So. Und nun weswegen das Ganze? Wenn am PC ein Programm abschmiert, wird es vom BS rausgeworfen und eventuell neu geladen und gestartet. Damit hat man immer die Anfangsbedingungen, die man laut Schulbuch erwartet. Wenn man hingegen auf nem µC sein Programm laufen hat, dann ist es durchaus wahrscheinlich, daß man einen Neu-Anlauf einiger Teile mal durchführen muß, weil sich eben was in der Außenwelt geändert hat. Ein BS, das einem die Aufräumarbeiten abnimmt, hat man da nicht. Nun könnte man die Generalkeule schwingen und nen kompletten Neuanlauf erzwingen, z.B. per Watchdog oder softwareausgelöstem Reset - je nach vorhandenem Controller. Aber das ist fast immer die unschönste Lösung. Also initialisiert man mit nem Aufruf der zugehörigen InitXYZ() die betroffenen Teile und die Sache ist erledigt. Aber dazu muß man es eben so halten, wie ich das beschrieben habe: kein "static", sondern Globalvariable, denn sie muß ja vom InitXYZ() auch erreichbar sein. Kein long abc=4711; sondern Trennung von Deklaration und Wertzuweisung, denn es muß ja beim Aufruf der Initialisierung des Moduls ohnehin getan werden. Kein Glauben, daß beim Anlauf in jeder Variable 0 oder eine Vorbelegung drinsteht, sondern das Wissen, daß dort bunter Käse drinsteht, solange InitXYZ() das nicht gerichtet hat. Ich hatte vor langer Zeit genau diese tollen Probleme mit dem Fat Filesystem von Chan. Der war auch so ein Gläubiger der Ausnullung, weswegen es regelmäßig zum Datencrash kam, wenn ein Benutzer die SD-Karte gewechselt hat, ohne brav zuvor auszumounten, denn die SD-Initialisierung (!!!) des FF verließ sich auf das Ausgenulltsein eines Pointers. Eben deswegen mein Zitat von Sam. Kurzum: Das Zitieren des Schulbuches ist das eine, das richtige Leben ist was anderes. W.S.
W.S. schrieb: > Wenn man hingegen auf nem µC sein Programm laufen hat, dann ist es > durchaus wahrscheinlich, daß man einen Neu-Anlauf einiger Teile mal > durchführen muß, weil sich eben was in der Außenwelt geändert hat. Ein > BS, das einem die Aufräumarbeiten abnimmt, hat man da nicht. > > Nun könnte man die Generalkeule schwingen und nen kompletten Neuanlauf > erzwingen, z.B. per Watchdog oder softwareausgelöstem Reset - je nach > vorhandenem Controller. > > Aber das ist fast immer die unschönste Lösung. Also initialisiert man > mit nem Aufruf der zugehörigen InitXYZ() die betroffenen Teile und die > Sache ist erledigt. > > Aber dazu muß man es eben so halten, wie ich das beschrieben habe: > kein "static", sondern Globalvariable, denn sie muß ja vom InitXYZ() Ok, du hast also eine sehr spezielle Anwendung mit seht speziellen Anforderungen, so dass dir die vom CRT vorgenommene Initialisierung des Static Storage nix nützt bzw. in einigen kalten Pfaden händisch initialisiert werden muss. Aber daraus zu folgern, dass die gleiche Herangehensweise für alle anderen Anwendungen zuträfe, und daraus enstsprechende Ratschläge abzuleiten ist einfach hanebüchen. > Nop schrieb: >> Das ist Unsinn, weil der Compiler sich beim Optimieren darauf verlassen >> darf, daß ein Startupcode existiert, der globale Variablen >> standardkonform initialisiert. > > Mir ist wirklich kein C-Compiler bekannt, der selbst bei > ausgiebigster Optimierung ganze Anweisungen, mit denen einer Variable > ein Wert (0 oder sonstwas) zugewiesen wird, einfach wegläßt. Selbst der > knöselige GCC macht sowas nicht. ACK. Ich wüsste nicht, wie ein Compiler das ausnutzen sollte. Hier hat "Nop" was aus der Unsinn-Zaubertüte gezaubert. > Ich hatte vor langer Zeit genau diese tollen Probleme mit dem Fat > Filesystem von Chan. Der war auch so ein Gläubiger der Ausnullung, > weswegen es regelmäßig zum Datencrash kam, wenn ein Benutzer die > SD-Karte gewechselt hat, ohne brav zuvor auszumounten, denn die > SD-Initialisierung (!!!) des FF verließ sich auf das Ausgenulltsein > eines Pointers. Eben deswegen mein Zitat von Sam. Das hat nix mit "Glaube an Ausnullung" zu tun, sondern liest sich wie ein Bug im FS. > Kurzum: Das Zitieren des Schulbuches ist das eine, das richtige Leben > ist was anderes. Ok, dein "richtiges" Leben besteht also nur aus Anwendungen mit der von dir geforderten Warmstartfähigkeit einzelner Komponenten...
Johann L. schrieb: > Aber daraus zu folgern, dass... Nun, das ist die wissenschaftlich begründete Herangehensweise. Wenn eine Sache, die man zuvor generell ausgeschlossen hat, sich eben doch wenigstens einmal (und das verifizierbar) ereignet, dann ist das generelle Ausschließen schlichtweg ein Fehler. Hier in diesem Thread eben ein Denkfehler, der da sagt: "wenn der Compiler und der Startupcode völlig richtig und bugfrei sind, dann ist es völlig ausgeschlossen daß.." - nun, ich habe es erlebt, das ist das "Eine Mal", was ausreichend ist zum Stürzen der vorherigen Behauptung - und andere erleben es offenbar auch gelegentlich und fragen dann hier an, warum sie ihre schöne C-Welt nicht mehr verstehen. Und noch was Praktisches dazu: Wenn man ausgiebig mit voreingestellten globalen Variablen arbeitet, dann müssen die ja im Flash vorgehalten werden und es braucht Code, um sie in den RAM zu befördern. Wenn man static Variablen benutzt, dann müssen die ebenfalls so vorgehalten werden. Das kostet Platz. Vermutlich nicht sonderlich viel, aber wenn man es aufrechnet gegen das dedizierte Initialisieren in einer Init-Funktion, dann wird sich da wohl fast eine Patt-Situation ergeben. Der Unterschied ist der, den Max nannte. Er besteht darin, daß man bei der Initxyz()-Version (die ich präferiere) sich auf garnix zu verlassen braucht und es kostet trotzdem fast nix mehr an Code und Zeit. Kurzum, meine Herangehensweise ist von Hause aus stabiler und zuverlässiger. Aber all diejenigen, die hier das Schulbuch zitieren wollen, werde es wohl nicht einsehen. W.S.
Johann L. schrieb: >> Mir ist wirklich kein C-Compiler bekannt, der selbst bei >> ausgiebigster Optimierung ganze Anweisungen, mit denen einer Variable >> ein Wert (0 oder sonstwas) zugewiesen wird, einfach wegläßt. Selbst der >> knöselige GCC macht sowas nicht. > > ACK. Ich wüsste nicht, wie ein Compiler das ausnutzen sollte. Hier hat > "Nop" was aus der Unsinn-Zaubertüte gezaubert. Genau das ist aber doch hier - wenn ich nicht völlig falsch liege - passiert? Der Compiler hat eine Initialisierung mit 0 festgestellt und - statt die Zuweisung stehen zu lassen - die Variable stattdessen ins .bss gesteckt. Zuweisung? - wegoptimiert.
W.S. schrieb: > Ich hatte vor langer Zeit genau diese tollen Probleme mit dem Fat > Filesystem von Chan. Der war auch so ein Gläubiger der Ausnullung, > weswegen es regelmäßig zum Datencrash kam, wenn ein Benutzer die > SD-Karte gewechselt hat, ohne brav zuvor auszumounten, denn die > SD-Initialisierung (!!!) des FF verließ sich auf das Ausgenulltsein > eines Pointers. Eben deswegen mein Zitat von Sam. Du willst und kannst den Unterschied zum eigentlichen Thema anscheinend nicht verstehen. Das hast du ja nun in vielen Beiträgen ausreichend bewiesen. Ein nicht genullter Pointer bei SD-Kartenwechsel ist ein Programmierfehler, weil der Programmierer dies schlicht vergessen hat. Eine Clib, die das bss-Segment nach einem Kaltstart nicht nullt, ist fehlerhaft, weil nicht der C-Spezifikation entsprechend. Das eine hat mit dem anderen nichts zu tun. Ob jetzt bei einem Warmstart die Initialisierungen der clib duechlaufen wird, oder nicht, muß im Einzelfall geklärt und berücksichtig werden. Warmstart kann ja alles mögliche sein. Daraus jetzt abzuleiten, daß man immer und überall besser seine Variablen vollständig von Hand ininitalieren muß, ist abstrus. Man muß einfach nur wissen, was man tut. Oliver
W.S. schrieb: > Johann L. schrieb: >> Aber daraus zu folgern, dass... > > Nun, das ist die wissenschaftlich begründete Herangehensweise. Die "Logik" deiner Schlussfolgerung ist, aus einem Spezialfall eine Allgemeingültigkeit abzuleiten — nämlich basierend deiner App mit bestimmter Warmstartfähigkeit einen Kreuzzug gegen static und crt vom Zaun zu brechen. Aus einer allgemeingültigen Aussage kann man immer einen enthaltenden Spezialfall folgern, aber die Umkehrung gilt i.A. nicht. Daraus, dass 2 eine Prinzahl ist, kann man weder folgern, dass alle ganzen Zahlen Primzahlen sind, noch dass alle Primzahlen gerade sind, noch dass alle Primzahlen < 10 sind.
W.S. schrieb: > Vermutlich nicht sonderlich viel, aber wenn > man es aufrechnet gegen das dedizierte Initialisieren in einer > Init-Funktion, dann wird sich da wohl fast eine Patt-Situation ergeben. Der Startup-Code lädt in einer Schleife vom Flash ins RAM, d.h. je Bytevariable wird auch nur ein Byte Flash benötigt. Die Kopierroutine fällt nur einmalig an. Jede explizite Zuweisung benötigt aber jeweils 6 Byte (LDI+STS). Es lohnt sich also, zu überlegen, wo man den 6-fachen Codeoverhead wirklich braucht und wo nicht.
Also ich würde Ausführungen zum Thema C-Programmierung von jemandem, der dazu rät static "egal wo" zu meiden, mit äußerster Vorsicht genießen :D
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.