Forum: Compiler & IDEs Typvereinbahrungen, array von Zeigern auf Flash


von Christian P. (sarstein)


Angehängte Dateien:

Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von sarstein (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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

von sarstein (Gast)


Lesenswert?

Hallo,

dachte sowas geht in einem Rutsch schon bei der Initialisierung.
Danke Karl Heinz.

Gruß
Christian

von Karl H. (kbuchegg)


Lesenswert?

Da könnte dieser Thread
Beitrag "String Array im Flash einfacher geworden?"
für dich unter Umständen interessant sein.

von sarstein (Gast)


Angehängte Dateien:

Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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)

von sarstein (Gast)


Lesenswert?

...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

von sarstein (Gast)


Lesenswert?

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

von sarstein (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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 ?

von sarstein (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von sarstein (Gast)


Angehängte Dateien:

Lesenswert?

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

von Werner B. (werner-b)


Lesenswert?

1
 c = *(message_pt->txtnn_pt); //Fehler
should read
1
 c = pgm_read_byte(message_pt->txtnn_pt); // OK

von sarstein (Gast)


Lesenswert?

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

von sarstein (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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];

von sarstein (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von sarstein (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.