Hallo zusammen, nachdem mein Latein am ende ist, bitte ich hier im Forum um Hilfe. Aufgabe: Ich will Stringkonstanten im Flash ablegen und über ein Array <txt(1)_a> von Zeigern auf einzelne Strings zugreifen. Die Struktur <message> enthält stringrelevante Daten und wird mit einem Zeiger <message_p> für eine im beigefügten Codeschnipsel nicht dargestellte Weiterbearbeitung benutzt. Meine Fragen: a) Compilerwarnungen Die Arraydefinition und Initialisierung mit <int8_t *txt_a[]> verursacht Warnungen, egal ob Flash oder RAM benutzt wird, mit dem Datentyp <char> erfolgt keine Warnung? Warum bringen die 2. und 3. Anweisung in der Funktion <getMessage> ebenfalls Warnungen? Die 3. und 4. Anweisung (mit strlen()) funktionieren auch nicht. b) In der Includedatei <stdint.h> gibt es Typdeklarationen mit signed/unsigned char aber nich mit char allein, kann es daran liegen? c) Die Funktion <strlen()> die in <string.h> deklariert ist, liefert einen Wert vom Typ <size_t> zurück, aber wo ist <size_t> deklariert? Ich habe angenommen das müsste beim AVR 8Bit, also <int8_t> bzw. <uint8_t> sein, führt aber beides zu Warnungen. Ausserdem funktionieren beide Anweisungen hier nicht, d.h. in <txtlen(1)> steht falsches drin. d) Kann das Auslesen einzelner Arrayinhalte aus dem Flash so wie in den ersten beiden auskommentierten Anweisungen in der Funktion <getMessage> überhaupt so funktionieren? Kurzbeschreibung des angehängten Codeschnipsels: Das Array <char *txt1_a[]> ist nur wegen der Typvereinbarung mit <char> aufgeführt. Entsprechend auch alle anderen Erweiterungen mit diesem Datentyp. Der enum Typ dient nur der besseren Lesbarkeit. Ich benutze WinAVR 20090313 und AVR-Studio V4.18 build 692. Das ganze wird mit der Optimierung -O0 und debug Informationen für einen AVR 8515 übersetzt und soll erst mal auf einem STK500 laufen. Warnungen kann man ignorieren, aber ich möchte halt wissen wo sie herkommen und es ist mir lieber wenn ich keine sehe. Wäre schön wenn da jemand brauchbare Tipps hätte. Codeschnipsel im Anhang Schon mal danke im Voraus Christian
a+b) Ein "char" ist weder signed noch unsigned. Es ist ein Datentyp ohne implizite Signedness (im Gegensatz zu z.B. "int"). Grundregel: Benutze "char" wirklich nur dann, wenn es auch tatsächlich ein Zeichen ist. Wenn du eigentlich einen kleinen Integer haben willst, dann benutze entweder "signed char"/"unsigned char", oder int8_t/uint8_t. c) stddef.h d) Im Prinzip schon, aber wenn errorTxt_2a_p in der Art definiert ist, wie txt_a und txt1_a es andeuten, dann sind die Texte selber gar nicht im Flash, sondern nur die Pointer.
Christian P. schrieb: > Meine Fragen: > a) Compilerwarnungen > Die Arraydefinition und Initialisierung mit <int8_t *txt_a[]> > verursacht Warnungen, egal ob Flash oder RAM benutzt wird, > mit dem Datentyp <char> erfolgt keine Warnung? Das kann gut sein. > Warum bringen die 2. und 3. Anweisung in der Funktion <getMessage> > ebenfalls Warnungen? > Die 3. und 4. Anweisung (mit strlen()) funktionieren auch nicht. > b) In der Includedatei <stdint.h> gibt es Typdeklarationen mit > signed/unsigned char aber nich mit char allein, kann es daran liegen? signed char, unsigned char und char sind drei verschiedene Typen. Wenn du Zeichen darstellen willst, nimm char. Dafür ist er da, und nur dafür. > c) Die Funktion <strlen()> die in <string.h> deklariert ist, liefert > einen > Wert vom Typ <size_t> zurück, aber wo ist <size_t> deklariert? stddef.h und andere (z.B. stdlib.h) > Ich habe angenommen das müsste beim AVR 8Bit, also <int8_t> bzw. > <uint8_t> sein, führt aber beides zu Warnungen. Wäre der nur 8 Bit groß, könnte es keine Variablen geben, die größer als 255 Bytes sind, denn sizeof liefert auch einen Wert vom Typ size_t zurück. > Ausserdem funktionieren beide Anweisungen hier nicht, d.h. in > <txtlen(1)> steht falsches drin. Da sehe ich eigentlich keinen Grund dafür. > d) Kann das Auslesen einzelner Arrayinhalte aus dem Flash so wie in den > ersten beiden auskommentierten Anweisungen in der Funktion > <getMessage> > überhaupt so funktionieren? Nein, da es sich um ein Array aus Zeigern handelt und diese Arrayinhalte daher Zeiger sind. Die Strings stehen trotzdem im RAM. Dein pgm_read_word würde sogar noch funktionieren, weil es eben genau den Zeiger aus dem Array liest, aber das strlen_P nicht, denn das erwartet den String im Flash. > Kurzbeschreibung des angehängten Codeschnipsels: > Das Array <char *txt1_a[]> ist nur wegen der Typvereinbarung mit <char> > aufgeführt. Entsprechend auch alle anderen Erweiterungen > mit diesem Datentyp. Warum? Der sollte so sein, weil er auf einen String zeigt. > Der enum Typ dient nur der besseren Lesbarkeit. Das ist ganz allgemein der Sinn von enum-Typen ;-) > Warnungen kann man ignorieren, aber ich möchte halt wissen wo sie > herkommen und es ist mir lieber wenn ich keine sehe. Sehr guter Ansatz. Anmerkung: Für kleine Integer, nimm int8_t oder uint8_t und für Zeichen nimm char. Du machst das aus irgendeinem Grund genau umgekehrt, und deshalb bekommst du auch so viele Warnungen und mußt überall casten.
Guten Morgen Schon mal danke für eure raschen Antworten. Jetzt ist mir auch der Unterschied zwischen <char> und <(u)int8_t> klar. Die Headerdateien stddef.h, inttypes.h, stdint.h, string.h, pgmspace.h, etc. habe ich alle schon mit eingebunden gehabt. Die Definition <errorTxt_2a_p> ist identisch zu <txt(1)_a>, hab hier nur die Korrektur des Namens beim rauskopieren aus der Originaldatei übersehen. Tut mir leid, dass das irreführend war. Eigentlich wollte ich bei dem Konstrukt die Texte (das werden noch mehr) und die Pointer im Flash haben. Nur wie muss dann die Syntax dafür aussehen? Da trete ich momentan auf der Stelle. Da fällt mir noch eine Frage ein. Die enum <errortext_e> und die Stringkonstanten <txt_a> sind namentlich identisch, müssen aber quasi "zu Fuß" auf Gleichheit gehalten/überprüft werden und das ist fehlerträchtig. Gibt es da in C eine (fertige) programmiertechnische Möglichkeit die beiden inhaltlich synchron zu halten? Guten Start in die neue Woche Christian
sarstein schrieb: > Eigentlich wollte ich bei dem Konstrukt die Texte (das werden noch mehr) > und die Pointer im Flash haben. Nur wie muss dann die Syntax dafür > aussehen? Da trete ich momentan auf der Stelle. So wie hier http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Array_aus_Strings_im_Flash-Speicher
Hallo, dachte sowas geht in einem Rutsch schon bei der Initialisierung. Danke Karl Heinz. Gruß Christian
Da könnte dieser Thread Beitrag "String Array im Flash einfacher geworden?" für dich unter Umständen interessant sein.
Hallo Karl Heinz die 2-stufige Initialisierung ist zunächst mal ok. Es gibt auch keine Warnungen mehr. Der letzte Tip ist natürlich reizvoll, werde ich noch probieren. Was aber gar nicht geht ist <strlen_P()>, das ergibt jedesmal einen crash. Hab das auch nochmal im RAM mit <strlen()> probiert, auch da krachts. Wie ist den das? In der Headerdatei <string.h> ist -neben anderen Funktionen- der Prototyp der Funktion <strlen_P()> als extern angegeben. Ist die Funktionsdefinition davon im gcc schon implementiert oder muß da vielleicht noch eine library mitgeladen werden? In den FAQ's find ich da auch nichts passendes. ciao Christian
sarstein schrieb: > Hallo Karl Heinz > > die 2-stufige Initialisierung ist zunächst mal ok. Es gibt auch keine > Warnungen mehr. Der letzte Tip ist natürlich reizvoll, werde ich noch > probieren. > Was aber gar nicht geht ist <strlen_P()>, das ergibt jedesmal einen > crash. Bei mir nicht. Hab dein Beispiel probiert. Klappt einwandfrei (Und ich wüsste auch nicht warum das crashen soll)
...na dann muß ich wohl mal weitersuchen, vielleicht liegt das auch an meinem Rechner. Trotzdem schon mal vielen Dank für die Unterstützung auch den beiden anderen. Ich melde mich wieder. Servus Christian
Hallo zusammen, suche schönes, buntes Seil mit 7-fach Knoten;-). Spaß beiseite. Platte geputzt, AVR-Studio (jetzt V4.18, build 684) neu installiert, Virenscanner aus uvam., aber ich bin soweit wie heute mittag. Mit dem AVR-Studio Simulator läuft das zuletzt geladene Progrämmchen <test3.c> bis zur Anweisung <l = (uint8_t)strlen_P(pt);> und beim Ausführen der Anweisung landet der gelbe Pfeil vom Simulator an der schließenden Klammer von <main()>. Irgendwann hatte ich den Quellcode auch mal in Assembler vorliegen, da konnte man mit F11 fehlerfrei durchsteppen. Kann das aber leider nicht mehr reproduzieren. Beim anschließenden Versuch im C-Quellcode trat das zuvor beschriebe (Absturz)Verhalten wieder auf. Sollte hier noch jemand Rat wissen, bitte melden. Mir brummt der Kopf, morgen geht es weiter! Schönen Abend Christian
Hallo zusammen, das Problem hat sich geklärt. Nach dem Tausch der Speicherriegel im Rechner funktioniert jetzt auch bei mir das Codeschnipsel und der Rest. Nach der vorausgegangenen Neuinstallation liefen auch andere Programme instabil. Ich habe dann einen alten Rechner im Keller ausgegraben und AVR Studio darauf installiert und plötzlich funktionierte es. Ein freeware Testprogramm auf dem instabilen Rechner zeigte mir dann einen Speicherfehler an. @Stefan Ernst Doch noch eine Frage zu den Typdefinitionen. Was ist dann der Unterschied zwischen <unsigned char> zu <uint8_t> bzw. <signed char> zu <int8_t>? Sind <xchar's> z.B. für arithmetische Operationen ungeeignet oder unzulässig? Hab' ein bisschen rumprobiert, bei einfachen Operationen haben die <xchar's> schon funktioniert, nur der Compiler hat manchmal gemeckert wenn ich <xchar's> und <xint's> gemischt habe. Das dürfte aber eher für die Qualität des gcc sprechen. Gruß Christian
sarstein schrieb: > Doch noch eine Frage zu den Typdefinitionen. Was ist dann der > Unterschied zwischen > <unsigned char> zu <uint8_t> bzw. > <signed char> zu <int8_t>? Bei unsigned char und uint8_t wird es auf den meisten Systemen keinen Unterschied geben. 'unsigned char' ist in C die Schreibweise für 'ein Byte'. uint8_t ist die portable Schreibweise für 'einen unsigned Wert mit 8 Bit'. Jetzt gibt es natürlich auch Rechner, die als kleinste Einheit kein Byte mehr haben, sondern zb 16 Bit. Bei denen ist ein unsigned char dann auch 16 Bit groß, allerdings wird dann ein uint8_t auch 16 Bit haben, weil es ja etwas kleiners per Definition auf der Hardware gar nicht gibt. Oder aber der Compiler packt 2 uint8_t in 16 Bit rein und spickt das Ganze dann mit zusätzlichem Code, um die Einzelteile beim Zugriff auseinanderzupfriemeln. Interessanter ist daher der Fall von int und int16_t Ein int ist per C Definition, der "bevozugte" Datentyp auf einem Rechner (was immer auch bevorzugt heißen mag, aber mindestens 16 Bit). ein int16_t hat exakt 16 Bit, ein plain vanilla int kann auch mehr haben. die Datentypen mit den Zahlen gestatten mir also eine bessere Steuerung darüber, was ich eigentlich haben will, während der C Compiler bei den 'alten generischen' Datentypen dann doch sehr viele Freiheiten hat. > Sind <xchar's> z.B. für arithmetische Operationen ungeeignet oder > unzulässig? Was sind xchar's ?
Hallo Karl Heinz xchar stand stellvertretend für singned char bzw. unsigned char. Also aus deiner Erklärung schließe ich, daß bei Berücksichtigung solcher Typdefinitionen C-Programme auch portabler für andere Plattformen sind. Habe darüber in diversen mir vorliegenden Büchern leider nichts aussagefähiges gefunden. Nochmals vielen Dank für deine ausführliche Erklärung. Gruß Christian
sarstein schrieb: > Hallo Karl Heinz > > xchar stand stellvertretend für singned char bzw. unsigned char. > > Also aus deiner Erklärung schließe ich, daß bei Berücksichtigung solcher > Typdefinitionen C-Programme auch portabler für andere Plattformen sind. > Habe darüber in diversen mir vorliegenden Büchern leider nichts > aussagefähiges gefunden. LOL Die Dinger sind relativ neu. Wobei: relativ ist gut. Sie sind schon älter als 10 Jahre. Allerdings muss man sagen, dass diese Datentypen im Dekstop-Programmierbereich nicht sehr verbreitet sind. Auf einem PC macht sich kaum wer Gedanken über die Bitbreite von Variablen. Hauptsache viel! Meistens sind die Dinger so definiert typedef unsigned char uint8_t; typedef signed char int8_t; und damit ist ein uint8_t einfach nur ein anderer Name für unsigned char.
Hallo zusammen Habe immer noch das Problem mit dem Array of pointers auf Stringkonstanten. Nach Einbau der hier erhaltenen Informationen in die SW lief das nicht. Also hab ich weiter probiert. Dasselbe anstatt ins flash einmal ins RAM. Die Zuweisung der Pointer aus dem Pointerarray schlägt auch da fehl. Wenn ich die Pointer der der Stringkonstanten direkt verwende ist es ok. Was mache ich da falsch? Kann es sein, dass die Initialisierung des Pointerarrays auf die Stringkonstanten nicht funktioniert? Würde mich um Unterstützung freuen. Gruß Christian
1 | c = *(message_pt->txtnn_pt); //Fehler |
should read
1 | c = pgm_read_byte(message_pt->txtnn_pt); // OK |
Hallo Werner, das war's. Schon getestet, läuft. Vielen herzlichen Dank für die Korrektur. Dachte die Zuweisung über den pointer alleine würde reichen! Schönes WE & Gruß Christian
Hallo Werner nachdem das Auslesen aus dem flash jetzt tadelos funktioniert, habe ich mir das hier zuletzt mitgeschickte Codeschnipsel mit derselben Funktionalität, aber aus dem RAM nochmal angesehen, das geht nämlich nach wie vor nicht. Die Initialisierung des array of pointers <*txt_a[]> ist aber -anders als im Kommentar geschrieben- in Ordnung. Nur die Zuweisung an die beiden Strukturelemente <msg_pt->pt> und <msg_pt->len> klappt nicht. Hab da noch rumprobiert, bin aber dabei nicht vorwärts gekommen. Bitte kannst du dir das noch mal ansehen und mich gegebenenfalls korrigieren. Schon mal danke für die Mühe. Gruß Christian
Auch wenn ich nicht Werner bin:
1 | msg_pt->pt = (char*)&txt_a[msg_pt->idx]; |
->
1 | msg_pt->pt = txt_a[msg_pt->idx]; |
Hallo Stefan läuft, danke. Hab mich an Werner gewandt, weil der mir zuvor geholfen hat. In Zukunft wende ich mich an alle.;-) Ich war auf den Adressoperator & fixiert. Daß der Name eines Vectors einer Adresse entspricht war mir schon klar, aber warum ignoriert der Compiler das nicht, sondern übersetzt das so, daß es nicht funktioniert? Wie auch immer, es funktioniert, allerdings erhalte ich ohne cast auf (char*) die Warnung: "warning: assignment discards qualifiers from pointer target type" mit cast kommt keine Warnung. Trotzdem Danke für die Hilfe. Gruß Christian
sarstein schrieb: > Ich war auf den Adressoperator & fixiert. Daß der Name eines Vectors > einer Adresse entspricht war mir schon klar, aber warum ignoriert der > Compiler das nicht, sondern übersetzt das so, daß es nicht funktioniert? Weil das etwas ganz anderes macht. txt_a[msg_pt->idx] liefert den Inhalt von txt_a und zwar konkret vom Element msg_pt->idx, der seinerseits wieder ein Pointer ist. &txt_a[msg_pt->idx] liefert die Adresse, an der dieses Element gespeichert ist. Wenn du da unsicher bist, hilft es oftmals sich die Datenstruktur aufzumalen. > Wie auch immer, es funktioniert, allerdings erhalte ich ohne cast auf > (char*) die Warnung: > "warning: assignment discards qualifiers from pointer target type" > mit cast kommt keine Warnung. Der cast ist in diesem Fall die falsche Lösung. txt_a[msg_pt->idx] ist vom Datentyp her ein const char * Die Variable, an die du den Pointer zuweist, ist aber nur ein char * Mach daraus einen const char * und der Compiler hat keinen Grund mehr zum meckern.
Hallo Zeiger haben es eben in sich und aufmalen hilft, wenn man es richtig macht. Hatte ich gemacht, aber leider war auch da ein Fehler! Mit dem cast das war ein ziemlicher Gedankenfehler meinerseits. Ich bin fest davon ausgegangen, wenn ich in der Typdeklaration für die Struktur den pointer als const char festlege, dann kann ich den pointer in der Struktur selbst nicht mehr verändern, nicht aber daß dieser pointer auf einen Wert vom Typ const char zeigt. Man lernt nie aus. Die Erklärung hat mir sehr geholfen, danke. Gruß Christian
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.