Hallo Leute! Wenn das stimmt, was ich vermute, dann bin ich ein bischen frustriert. Zunächst hatte ich mich gewundert, das im AvrStudio auch meine Programm-Konstanten im "data" Bereich auftauchten (Compiler: gcc). Ich hab dann alle Texte (Menues usw.) als "const" definiert, und war der Auffassung, dass diese dann logischerweise im "Program"- Bereich landen muessten, so wie ich das vom 8051 kenne. Dort gibt es den "movc" Befehl, und wenn man "const" - Strings benutzt, muss man sich weiter keine Gedanken machen: die Sachen landen dann alle im eprom und gut isses. Nachdem nun meine Applikation nicht mehr lief (weil der data-bereich voll war) hab ich hier im Forum gesucht. Wenn ich's richtig verstanden habe, dann muss man tatsächlich solche 'const's explizit anders programmieren (pgmspace.h), wenn man sie nicht im data-Bereich haben will? DAS WAER' JA SCHEUSSLICH! Vermutlich habe ich dann auch graessliche Laufzeiten, wenn ich Texte aus dem PgmSpace verarbeiten will? Ist das so? Oder hab ich nur nicht das Richtige gefunden? Beim 8051 hatte ich auch mit nur 256 Byte Ram doch immerhin die Möglichkeit, volle 64K für 'const' daten und Programm zu haben, ohne so einen Zirkus wie pgmspace.h. Und nochwas (da hab ich aber ehrlich gesagt noch nicht weiter gesucht): Mein At90s8535 hat 512 Byte Ram. "isp" meldet mir aber " Signature: ATMEL AT90S8535 8kB Flash operates with: 8192 Bytes Flash and 256 Bytes data-memory" was ja eigentlich bei einem 8-Bitter auch logisch ist. Wie macht man sich die 512 Byte zunutze? e.
So geht es: Deklaration/Definiton: static const unsigned char unshifted[][] PROGMEM = { ... }; PGM_VOID_P index= unshifted; Zugriff mit: pgm_read_byte( unshifted++ ); Das liegt daran, dass der GCC normalerweise für von Neumann-Architekturen Code erzeugt. Darum die spezielle Deklaration.
"const" ist in C übrigens -- entgegen weitläufiger Auffassung -- nicht die Deklaration einer Konstanten, sondern lediglich die Aufforderung an den Compiler, Zugriffe auf das so bezeichnete Objekt, die zu einer Manipulation des Objektes führen können, anzuwarnen. (In C++ ist das anders.) Wenn manche Compiler das "const" als Pseudo-Speicherklasse benutzen, ist das IMHO eine Verletzung des C-Standards. Aber was soll's, diese Compiler implementieren schließlich auch PORTA.0 oder sowas, und das hatten wir neulich schonmal, das läßt sich mit keiner C-Syntax rechtfertigen (auch wenn es schön bequem aussieht). > Vermutlich habe ich dann auch graessliche Laufzeiten, wenn ich Texte > aus dem PgmSpace verarbeiten will? Ist das so? ,,gräßliche Laufzeiten'' wäre übertrieben, aber durch die Harvard- Architektur hast Du beim AVR zwangsweise einen Overhead, wenn Du konstante Daten im Flash ablegen möchtest, da sie zur Laufzeit erst von da in den RAM bzw. in Register geladen werden müssen. Dabei ist es komplett unabhängig, ob dieses Laden explizit erfolgt (wie durch pgm_read_byte() beim AVR-GCC) oder implizit im Rahmen einer normalen Zuweisung (wie vielfach bei anderen AVR-Compilern) -- intern muß in jedem Falle ein LPM-Befehl benutzt werden. Dafür spart man eben RAM. Nu ja, der Vergleich mit dem 8051 hinkt ein wenig: der hat (beim Standardchip) 12 Takte gebraucht, um überhaupt mal den Finger zu rühren, während der AVR in dieser Zeit schon eine komplette Multiplikation hinter sich gebracht haben kann. ;-) > Und nochwas (da hab ich aber ehrlich gesagt noch nicht weiter > gesucht): Mein At90s8535 hat 512 Byte Ram. "isp" meldet mir aber > " Signature: ATMEL AT90S8535 8kB Flash > operates with: 8192 Bytes Flash and 256 Bytes data-memory" > was ja eigentlich bei einem 8-Bitter auch logisch ist. Warum solle das logisch sein? Der (derzeit) größte AVR hat 4 KB RAM (und kann ohne Banking mit externem RAM auf 64 KB ausgebaut werden), was soll daran ungewöhnlich sein? Der Z80 konnte ebenfalls 64 KB adressieren, auch wenn es ein 8-Bit-Prozessor ist. RAM-Adressen sind halt allesamt 16 bit breit. Du hast drei Speicherbereiche: Flash-ROM, SRAM, und EEPROM. Der SRAM wird Dein Programmiertool nicht interessieren: es kann darauf sowieso nicht zugreifen. Was dort als data-memory bezeichnet wird, dürfte der EEPROM sein (der sowohl vom Programmer als auch von der Applikation aus zugreifbar ist).
Hm. Die Sache mit dem const - Schlüsselwort liest sich im "ANSI and ISO Sandard-C, Programmers Reference" so: "A const qualified type indicates that access to the designated data object cannot alter the value stored in the data object. All other data objects can have their values altered". Ansi und Iso - Standard wohlgemerkt (Plauger & Brodie 1992). Zum 8051 - ich will hier ja keinen Wettbewerb veranstalten. Was glaubst Du wohl, warum ich auf die AVR's umgestiegen bin? Ist doch gar keine Frage, das die Dinger sehr viel performanter sind, und jede Menge Vorteile haben. Aber es ist doch auch verständlich, dass man zuweilen dem ein oder anderen Goodie seines bisherigen "Lieblings-Prozessors" nachweint (vor allem dem Datentyp "bit"). Ich beschäftige mich erst seit dem Wochenende mit den AVRs, und bin nach wie vor begeistert. Trotzdem ist die anfängliche Euphorie auch ein wenig der Ernüchterung gewichen (ein normaler Vorgang). Denn bei Licht besehen erweisen sich einige der Vorteile als weniger gross, als sie in den Marketingmassnahmen der Hersteller zunächst erscheinen. Zum Beispiel: die eben erwähnte Speicherklasse Bit. wenn so ein 8051 auch wenig Speicher hat, so kann man da in einem einzigen Byte bereits 8 Flags speichern. Bei den AVRs brauchste dazu 8 Byte. Da relativiert sich das mit dem Speicher schon ein wenig. Oder die Tatsache, dass ich keine v. Neumann-Boards damit bauen kann (muss ich ja auch nicht unbedingt, aber praktisch wars manchmal schon). Aber das ist eben der Preis der Integration und des Komforts. Wenn ich meine Speicherbausteien (RAM/ROM) extern aufbaue, kann ich sie natürlich auch verdrahten, wie ich will, logo. Im Übrigen gibts die 8051-Derivate bis 50 Mips - vergiss mal die 12 Takte, das war, wie Du selber sagst, der Core beim Standardchip, wie er ehemals von Intel und Siemens gebaut wurde. Spätestens seit Dallas oder SiLabs (ehem. Cygnal) ist das anders. > Warum solle das logisch sein? Stimmt, - ich bin mal wieder vom "internen" Speicher ausgegangen, wie ich ihn vom 8051 Kenne, okokok, Du hast recht ... Nur insofern muss ich einschränken, dass RAM-Adressen keineswegs immer 16 Bit breit sind. Nochmal 8051: das Interne Ram bei den 8051-ern war 7 (!) Bit breit, ergo auch seine (internen) RAM-Adressen. Erst beim 8052 wurde der Speicher um sagenhafte 128 Byte aufgestockt: das waren dann immerhin 8 Bit (interne) Ram-Adressen. Und da liegt halt auch mein Denkfehler: ich muss eben noch lernen, dass es hier nicht um den "internen" Prozessorspeicher geht, sondern um das bei anderen Prozessorarchitekturen extern vorhandene und "sichtbare" SRAM. Nur eben schon drin im Gehäuse. Das heisst dann aber auch nichts anderes, als das faktisch bereits ein Latch in duie AVRs eingebaut ist, weil 2^8 nunmal nur bis 256 reicht. e.
Grrr!! Und jetzt hab' ich das alles schön gemacht mit 1. Versuch: static const char *Menue[] PROGMEM = { ... }; Steht im AVRStudio trotzdem noch im data-Bereich. Ich sehe sie aber AUCH IM PROGRAMM-Bereich. 2. Versuch: static const prog_char *Menue[] = { ... }; Gleiches Ergebnis. Ich kapier da sowieso was nicht. Wenn ich den Chip programmiere, landet das Programm im Flash (was der Funktion nach einem Eprom entspricht). Dabei müssen nun auch meine Konstanten muessen ja irgendwo hin. Wo landen die? Wenn die Im Flash landen würden (ohne die pgmspace.h - Definitionen), dann müssten die ja bei Prozessorstart irgendwie in den Data-Bereich rüberkommen. WENN NICHT, wo landen sie dann? Sofort im Data-Bereich (schon bei der Programmierung?). Kann eigentlich nicht sein: bei Abklemmen von Vcc sind alle Daten weg. Dann wären auch die Konstanten weg, wenn sie in Data - Bereich liegen würden. Also: wohin werden die Texte bei der Programmierung geschrieben? Ich kapiers nicht. e.
@emax: Was das const angeht, so hat Jörg da recht, const ist kein Datentyp, sondern ein Typ Modifier. "Zum Beispiel: die eben erwähnte Speicherklasse Bit": Warum nimmst Du nicht ein Bitfeld? Das ist zwar von der Performance her weit vom 8051er entfernt, aber es braucht in Deinem Beispiel immerhin nur ein Byte anstatt 8. Die 8051-Derivate gibt es im Übrigen bis 100 Mips, dazu noch mit umfangreicherer Ausstattung, so z.B. mit zusätzlicher MAC-Einheit, dass in einigen Fällen kein DSP mehr nötig ist. Und wieso muss ein Latch in den AVR eingebaut sein, nur weil die Datenbreite 8 Bit ist? Das ist völlig unabhängig von der Adressbusbreite.
Die einzelnen Strings musst Du auch noch als PROGMEM deklarieren. In der Doku steht es so: #include <avr/pgmspace.h> const char foo[] PROGMEM = "Foo"; const char bar[] PROGMEM = "Bar"; PGM_P array[2] PROGMEM = { foo, bar }; int main (void) { char buf[32]; strcpy_P (buf, array[1]); return 0; }
@Holger >Was das const angeht, so hat Jörg da recht, >const ist kein Datentyp, Das sagt ja auch keiner. Natürlich ist const kein Datentyp. Sonst wäre ja z.B. "const int" ein Widerspruch in sich .... Es ging um die Frage, ob es die Deklaration einer Konstanten oder eine Aufforderung an den Compiler ist. Und da sagt die ANSI / ISO - Beschreibung schlicht etwas anderes als Jörg. Man könnte noch drüber nachdenken, wo da eigentlich der Unterschied ist. Derartige Prüfungen gibt es bei C (im Gegensatz zu C++) zur Laufzeit nicht. Deshalb ist bei C die Frage "Konstante oder nicht" im Grunde nur zur Compile-Zeit relevant. Denn dann und nur dann kann mir der Compiler einen Fehler melden. Hinterher ist's eh' zu spät, wenn man mal vom üblichen segfault absieht. Den musses -je nach Maschine- nämlich nicht zwangsläufig geben... Zu den Bits: so mach ichs ja auch, sogar performanter als bei den 8051 (die AVR sind eben einfach schneller). Es ist halt nur nicht so komfortabel. Ausserdem ist die Reihenfolge der Bits im Bitfeld nach C-Standard nicht definiert, und das ist - genau genommen - doch eine Einschränkung. Ist irgendwie nicht so schön, wenn z.B. Bitfeld.Bit7 an der 4. Stelle im Byte auftaucht... Aber Du hast schon recht: man kann damit leben. Für Dein Beispiel zum pgmspace vielen Dank, aber ich denke, so hab ich's gemacht: PGM_P ist nichts anderes als "const prog_char *" ... Aber Irgendwas hab' ich vielleicht doch übersehen ... Geb mir doch mal nen Tip, wo die Doku zu finden ist. In der avr-libc hab' ich nichts gefunden. Vielleicht hab' ich aber auch Tomaten auf den Augen ... Vor allem quält mich immer noch meine Kernfrage: "wohin werden die Texte bei der Programmierung geschrieben?" e.
Was die Bit-Vars angeht, so hast Du doch oben geschrieben, dass man bei den AVRs 8 Bytes braucht: "Bei den AVRs brauchste dazu 8 Byte", deshalb mein Einwand. Und schneller sind die nur gegenüber den Standard-8051ern. Es braucht beim AVR dafür drei Befehle anstatt einem. Und hast Du wirklich sowohl die Array-Variable als auch die einzelnen Stringkonstanten im Array getrennt als PGM deklariert? In der Doku steht es in der FAQ.
Hi der GCC hat halt Probleme mit der Harvard-Architektur. Wenn du den Komfort willst den du vom 8051 gewohnt bist (nicht der 8051 bietet diesen Komfort sondern der Compiler) mußt du halt einen Compiler kaufen der diesen Komfort bietet oder aber den AVR-Port des SDCC (der kann besser mit Harvard und unterschiedlichen Speicherklassen umgehen) zur Funktionsfähigkeit bringen. Ich wundere mich immer wieder wie manche Leute von kostenloser Software, mit der sie sogar Geld verdienen dürfen, gleiches erwarten wie von Software für einige k(Keil oder der IAR-Compiler). Und der GCC bietet, zusammen mit der AVRlibc, genug um auch professionelle Software zu entwickeln. Ich habe einfach das Gefühl du hast die Doku nicht ausreichend gelesen. Also hinsetzen und das hier http://jubal.westnet.com/AVR/doc/avr-libc-user-manual/FAQ.html#faq_rom_array lesen. Matthias
Mann oh Mann, was ist denn das für ein Gerede? Es wäre hilfreich, wenn Du mal wirklich lesen würdest, was ich geschrieben habe. Aber ich schreibs auch gerne nochmal: NATUERLICH SIND DIE AVR DEN 8051 ÜBERLEGEN! Natürlich habe ich gewechselt, weil das Gesamtpaket AVR/GCC das bessere ist! Deshalb HABE ICH JA gewechselt! Ausserdem klage ich nicht über mangelnden Komfort, sondern führe eine Diskussion über die Unterschiede. Und da gibts auf beiden Seiten Vor- und Nachteile. Ist denn das so schwer zu kapieren? Und wenn Du hiermit "....Ich wundere mich immer wieder wie manche Leute von kostenloser Software, mit der sie sogar Geld verdienen dürfen, gleiches erwarten wie von Software für einige ..." mich meinst, dann liegst Du schlicht schief. Erstens bin ich selber überzeugter Opensource-Mann (weshalb ich da, wo es geht, auch auf eine WinDAU Umgebung verzichte). Zweitens kenne ich zwar den Keil-Compiler, habe aber eine Menge Dinge auch mit dem SDCC gemacht. Und drittens erwarte ich nicht, dass der gcc das Selbe kann, wie der C51 auf den 8051. Mithin kostet der ja auch ein paar Märker. Wenn aber in einem Forum keine Diskussion geführt werden kann, weil sich irgendjemand ans Bein gepinkelt fühlt, oder weil man Angst haben muss, sonst irgendwelche heiligen Kühe zu schlachten, dann kannste das Forum eigentlich vergessen. Merke: eine Sache, die nicht verbessert werden kann, die gibts nicht. Und wenn die Diskussion darüber unerwünscht ist, dann wird die Entwicklung dieser Sache stehenbleiben. Also nochmal und gaanz deutlich: JA, DER AVR-GCC IST GANZ TOLL. ICH FREUE MICH, DASS ES IHN GIBT. Noch mal so was am Rande: ich habe meine ersten gcc-build auf einem 286er gemacht. Das ist sehr, sehr lange her, und war noch unter einer Kernelversion von 0.99-irgendwas. Ich finde diesen Compiler überragend, und habe damit eine Menge Produktionssoftware unter AIX und Solaris geschrieben. Also bleib mir " Leuten die von kostenloser Software erwarten ..." vom Hals. e. PS: meine Kernfrage ist immer noch offen. Da hier ja eine Menge Leute sind, die alle verfügbaren Dokumentationen von vorn bis hinten durchgelesen haben ;-)) müsste mir das doch einer beantworten können: "wohin werden die Texte bei der Programmierung geschrieben?"
Noch mal an Matthias, danke für den Link. Ich habe wirklich vor lauter Doku in den letzten Tagen nicht mehr gewusstm, wo ich schauen soll (AT90s8535, HD44780, AVR-LIBC, AVR-GCC, ISP, AVRCtrl etc. etc.). Die Seite erklärt wie's scheint genau, was man machen muss. Allerdings habe ich meine Menues mit typedef'ed structs angelegt, Da siehts ein bischen anders aus, ich mus mal schauen. manjana. e.
Und jetzt kann ich auch meine Kernfrage selber beantworten: .init4: Copies the .data section from flash to SRAM. Also sets up and zeros out the .bss section. In Unix-like targets, .data is normally initialized by the OS directly from the executable file. Since this is impossible in an MCU environment, avr-gcc instead takes care of appending the .data variables after .text in the flash ROM image. .init4 then defines the code (weakly bound) which takes care of copying the contents of .data from the flash to SRAM. Man muss es nur finden. Ok, jetzt wissen wirs, e.
Mußt ja hier nicht so rumschreien. Nochmal zu "const": nein, in C gibt es keine Konstanten, sondern bestenfalls Variablen, die sich nicht ändern lassen. Das ist ein Unterschied. Wenn Du richtige Konstanten brauchst, mußt Du den Präprozessor bemühen (dann gehen sie aber typischerweise aus der Debug-Info verloren). In dieser Hinsicht sind C++ oder Pascal anders: dort deklariert const wirklich eine Konstante, und es bleibt dem Compiler überlassen, ob er dafür tatsächlich erst Speicher belegt, oder ob er sie inline benutzt. Dank Harvard ist das beim AVR alles nicht so einfach. Wenn alle Konstanten automatisch im Flash landen würden, dann hättest Du ein Problem mit Ausdrücken wie: const char *foo = "hello world"; ... strcmp(something, foo) ... strcmp() muß in der Lage sein, beliebige Strings zu vergleichen. Wenn Du nicht gerade OO-typisches `late binding' haben möchtest, sollte bereits zur Compilezeit feststehen, wie auf den zugehörigen Speicher zuzugreifen ist. strcmp() erwartet einfach beide Argumente im RAM. Damit würde obige Operation (die durch Weiterreichen des Zeigers an Funktionen noch beliebig für den Compiler undurchsichtiger gemacht werden könnte ;-) aber fehlschlagen, wenn er automatisch alle string literals im ROM anlegt, da für ROM-Operationen strcmp_P() benutzt werden muß. In der Tat habe ich seltsamste Verrenkungen für ebendieses Problem im Code für die AVR Butterfly gesehen, der ja für den IAR geschrieben ist, der wiederum string literals von sich aus im ROM anlegt (da er im Gegensatz zum GCC besser mit Harvard umgehen kann). Seit ich das gesehen habe, sehe ich AVR-GCCs explizite Notwendigkeit, die Benutzung des ROM auf den Programmierer abzuwälzen, gar nicht mehr als so einen großen Nachteil an. ;-) Zurück zum Standard: ``If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. [...]'' Das ist alles, was der Standard dazu sagt (6.7.3 Type qualifiers). Anders gesagt: der Compiler darf das auch komplett ignorieren, er ist trotzdem noch konform. Eine Aussage wie die von Dir gemachte sehe ich als Anforderung durch den Standard nicht (sie beschreibt vielmehr die Intention, die dahinter steht). Bitfelder sind übrigens nicht wahllos anzuordnen (*): es ist lediglich implementierungsabhängig, ob sie ,,von links nach rechts'' oder genau andersrum implementiert werden. Außerdem, wenn Du Dir nur ein Bit merken willst (also nicht etwa auf IO-Ports zugreifen), kann es Dir ja auch egal sein, in welchem Bit er sich das wirklich merkt. ;-) (*) 6.7.2.1 Structure and union specifiers, Absatz 10: ``The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined.'' Es ist übrigens explizit gefordert, daß aufeinanderfolgend deklarierte Bitfelder auch aufeinanderfolgend zu speichern sind, sofern der Platz im Objekt das zuläßt. (Alles andere hätte ja auch keinen Sinn.) > "wohin werden die Texte bei der Programmierung geschrieben?" Welche Texte denn? Meinst Du string literals ganz allgemein? Das sind Variablen wie jede andere (s. o., um zu Standard-string-Funktionen trotz Harvard kompatibel zu bleiben). Folglich belegen sie RAM, genauso wie sie natürlich Flash-ROM belegen, um die Initialisierungswerte unterzubringen. Da wir hier nicht beim VM-Unix sind, können wir diese nicht via page fault zur Laufzeit aus der Datei lesen... Das ist nicht anders, als wenn Du int foo = 42; oder int char[] = {'H', 'e', 'l', 'l', 'o'}; schreibst. Lediglich Strings, die mit __attribute__((progmem)) deklariert worden sind (bzw. einem Makro, der das effektiv erledigt), belegen ausschließlich ROM, dafür müssen sie (weil der Prozessor das so will) halt zur Laufzeit erst aus dem ROM in den RAM bzw. Register kopiert werden, bevor man mit ihnen irgendwas machen kann. (Die Initialiserungswerte für die Variablen müssen natürlich auch kopiert werden, aber das passiert durch den C-Start-Code einmalig unmittelbar nach dem Reset.)
@Emax, "Ich hab dann alle Texte (Menues usw.) als "const" definiert, und war der Auffassung, dass diese dann logischerweise im "Program"- Bereich landen muessten, so wie ich das vom 8051 kenne. Dort gibt es den "movc" Befehl, und wenn man "const" - Strings benutzt, muss man sich weiter keine Gedanken machen: die Sachen landen dann alle im eprom und gut isses." Von welchen 8051 Compiler sprichst Du denn ? Beim Keil C51 ist es definitiv nicht so, da bedeutet const genau daß, was Jörg beschrieben hat. Der Keil hat dafür spezielle Schlüsselwörter (code, data, bdata, xdata usw.) um den Speicherbereich einer Variablen festzulegen. Und sämtliche string-Funktionen benutzen generic pointer, d.h. sie bekommen in einem 3.Byte übergeben, auf welchem Speichertyp sie arbeiten sollen. Peter
Hallo, wie waere es statt "const" zu benutzen, einfach eine (vielleicht) ueberholte Methode zu verwenden und zwar mit #define bzw. irgendwelche Macros oder so.... viellecht hab ich das hier auch nicht ganz verstanden... aber dann sollten die "Arrays" im Programm-Memory sein, oder??? Heinz
Jörg, was Du im, letzten Absatz schreibst "zur Laufzeit erst aus dem ROM in den RAM bzw. Register kopiert werden," hatte ich ja mittlerweile selbst rausgefunden. Trotzdem danke. Und mein Plauger & Brodie - Buch schmeiss' ich wohl weg ... Was Peter schreibt bringt mich wieder ins Lot: Du hast recht, ich hatte es einfach ausgeblendet: "code char Password [] = "xyz"; Allerdings gibt es das beschriebene strcpy Problem dort scheinbar zunächst nicht. Man kann beliebige Strings, code oder data, kopieren und vergleichen. Da es aber einen Unterschied geben MUSS (movc ist nicht mov), habe ich das ganze eben mal genauer unter die Lupe genommen. Und tatsächlich gibt es das Problem eben nur scheinbar nicht: der Compiler verdeckt das. Ein 3-Byte strcpy code->data: 99 Zyklen, data->data: 87 Zyklen. Also hab' ich einen tracedown der strcpy-Funktion gemacht, und siehe da: es gibt dort eine Sprungtabelle, die je nach übergebenem Pointer unterschiedliche Unterfunktionen anspringt. Diese Information wird in Registern übergeben. Die Zusammenhänge sind mir jetzt auch für den AVR-GCC klarer. Ich werd mir das auch mal beim SDCC anschauen... e.
> Man kann beliebige Strings, code oder data, kopieren und > vergleichen. Das schrob Peter aber schon: intern wird noch ein zusätzliches Attributbyte für jeden char * geführt, und die Entscheidung wird zur Laufzeit getroffen. Klingt nicht unelegant, macht allerdings einen Heidenaufwand (sizeof(char *) != sizeof(int *) == sizeof(any other *)) und kostet zusätzlichen Speicherbedarf (OK, minimal) und Laufzeit (für die Entscheidung, was zu nehmen ist). Außerdem entsteht zusätzlicher Bloat, wenn man in einer Applikation gar nicht alle möglichen Entscheidungspfade der generischen Funktionen braucht (weil man z. B. gar keine ROM-Strings hat). Soweit ich Peter mal verstanden hatte, ist das allerdings tunable, d. h. man kann das auch alles abschalten.
Hi kann man. Zumindest beim SDCC. Man sagt dem Pointer was er für ein Pointer ist. Also statt char * xdata char * Ersteres währe ein generic pointer der zur Laufzeit auf alle Speicherbereiche zeigen kann. Zweiteres ist ein Pointer der nur in den XRAM zeigen kann aber eben schneller im Zugriff ist. Matthias
@Jörg "Das schrob Peter aber schon: ..." Das "aber" kling nach Widerspruch. Dabei war das doch exakt das Thema meines letzten Beitrages, sogar mit präziser Code-Analyse. Der "Bloat" (ich nehme an, Du meinst toten Code) wird in der Praxis aber kaum Auswirkungen haben. Bei einem umfangreicheren Projekt werden vemutlich die meisten der möglichen Entscheidungspfade tatsächlich auch verwendet werden. Die wenigen, die übrig bleiben, dürften nur in Fällen stören, wo es wirklich auf jedes ROM-Byte ankommt. Das Code dann trotzdem äusserst kompakt ausfallen kann, zeigen die Keil-Ergebnisse. e.
Die Strings sind jetzt da, wo ich sie hin haben will. Wer weiss denn, wie ich noch diese Warnung weg bekomme, ich weiss nicht weiter: /*---------------------------------*/ typedef struct Menu { const char *Hdr1; const char **Hlp; } MENU; const char RomZ [] PROGMEM = ""; // "----+----1----+-" const char Help0 [] PROGMEM = "HilfeText1"; ; const char Help1 [] PROGMEM = "HilfeText2"; PGM_P Help [] PROGMEM = { Help0, Help1, RomZ }; const char MenuHdr0 [] PROGMEM = "Auswahl 1"; const char MenuHdr1 [] PROGMEM = "Auswahl 2"; static const MENU MainMenu [] PROGMEM = { { MenuHdr0, MenuHdr20, Help }, <------ main.c 499 { RomZ } }; /*---------------------------------*/ avr-gcc -c -mmcu=at90s8535 -I. -g -Os -Wall -Wstrict-prototypes -std=gnu99 main.c -o uhr2/main.o main.c:499: warning: initialization discards qualifiers from pointer target type
Gefunden. Ich muss "Help" zu (PGM_P *) casten. static const MENU MainMenu [] PROGMEM = { { MenuHdr0, MenuHdr20, (PGM_P *) Help }, <------ main.c 499 { RomZ } }; Damit, dass ich in einer struct - Deklaration nicht sowas struct foo { char **s1; // ok char *s3[]; // falsch } machen kann, ärgere ich mich jedesmal aufs Neue rum. Na denn. Alles happy. e.
> "Das schrob Peter aber schon: ..." > Das "aber" kling nach Widerspruch. Dabei war das doch exakt das > Thema meines letzten Beitrages, sogar mit präziser Code-Analyse. Nur daß Du eben Dinge analysiert hast, die gewissermaßen allgemein bekannt sind. ;-) > Der "Bloat" (ich nehme an, Du meinst toten Code) wird in der Praxis > aber kaum Auswirkungen haben. Mit Bloat ist der tote Code gemeint, ja. Außerdem hast Du halt die zusätzliche Ausführungszeit für das `late binding' (also die Entscheidung, die erst zur Laufzeit getroffen wird). Etwas ähnliches müßtest Du prinzipiell auch mit C++ machen können...
"... allgemein bekannt ..." Das erklärt Deinen Widerspruch erst recht nicht .... "...die zusätzliche Ausführungszeit für das `late binding' ..." Das ist wahr. Die Frage wäre, wieviel das ausmacht. Letztlich ist es immer die Entescheidung, ob man näher am Komfort und der Fehlersicherheit ist, oder näher am optimal schlanken Code. Die Extreme findest Du am Ende in C++ oder noch heftiger: Java. Die Konsequenzen sind dort am deutlichsten: jeder HiWi kann flugs mal ein kleines Java-Applet mit grafischer Schnittstelle schreiben, in C ist das nicht so einfach. In Java kümmert sich ein eigener Prozess ums Saubermachen (Housekeeping) in C musste das selber machen (ohne jetzt den grundsätzlichen Unterschied hinsichtlich Java-VM diskutieren zu wollen). Im Ergbenis ist C-Code mehrere 100 mal schneller als Java. Nach unten fortgesetzt findet sich das gleiche (wenn auch in abgeschwächter Form) im Vergleich C/Assembler wieder. Je mehr ich selber "von Hand" mache, desto schlanker kann das Resultat werden. Keine Frage. Vielmehr ist die Frage: was wollen Compilerbauer erreichen? Was wollen Compilerbenutzer haben? e.
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.