Forum: Mikrocontroller und Digitale Elektronik const char *text in C Struktur zur Laufzeit ändern


von C. L. (calle)


Lesenswert?

Hallo zusammen,

ich habe aus dem Netz ein Beispiel für ein Display Menü genommen
mit C Struktur. (dieses Beispiel wurde hier auch schon öfter 
angesprochen)
Da in dieser Strukur ein "const char *text" Pointer deklariert wird,
bin ich etwas gebunden was diese Texte angeht. Ich möchte den Menütext 
aber zur Laufzeit ändern
und weiß nicht wie, und ob das so geht.
Eigentlich ist eine const ja so erstmal nicht änderbar.


Hier die Strukturdefinition:
1
typedef struct Menuestruktur              // Struktur defnieren
2
{       
3
        const char *text;                 // Pointer auf Textfeld
4
        unsigned char num_menupoints;     // Variable für die Anzahl der Menüpunkte
5
        unsigned char up;                 // Variable für up
6
        unsigned char down;               // Variable für down
7
        unsigned char enter;              // Variable für enter
8
        unsigned char offset;      // Variable für zusätzliche Werteübergabe
9
        void ( *fp )(void);               // Pointer auf Void/Void Funktion
10
}MenuEntry;

hier werden die Menüstrings vergeben:
1
const char menu_000[] = "[Hauptmenue]        ";
2
const char menu_001[] = " ...anzeigen        ";
3
const char menu_002[] = " ...aendern         ";


nun das Menü organisieren:
1
MenuEntry menu[] =
2
{
3
        // Hauptmenü
4
        {menu_000, 11,  0,  0,  0,  0, 0},//1             
5
        {menu_001, 11,  1,  2,  12, 0, 0},//2 
6
        {menu_002, 11,  1,  3,  34,  0, 0},//3
7
        {menu_003, 11,  2,  4,  56,  0, 0},//4
8
9
10
        // Untermenü
11
        {menu_100,  22,  0,  0,  0,  0, 0},//5
12
        {menu_101,  22, 12, 13, 12,  0, funktionsaufruf}, //6 Funktion aufrufen bei Entertaste
13
14
};

in der Main wird dann das Anzeigen und das Hin- und herspringen 
aufgerufen.
Soweit funktioniert das auch alles.
Nun möchte ich die Texte, welche mit (const char menu_000[] = 
"[Hauptmenue]        ";)
vergeben wurden in der Main Schleife ändern.
Einmal widerspricht das ja der Konstantendefinition und zum Weiteren 
weiß nicht, wie ich das konform anstellen muss.

Mein Versuch zur Laufzeit in einer Abfrage in der Main den Text zu 
ändern:
1
    strcat(*txt_, "NeuText:            "); // neuen Text einbringen
2
    strcat(*txt_, "\0");                   // Stringende
3
    menu[1].text = *txt_[0];              // Zuweisung

Der Code compiliert zwar, zeigt aber bei der Zeile (menu[12].text = 
*txt_[0];)
eine Warnung "implicit conversion of int to ptr".
Wo hier int ist kann ich nicht nachvollziehen, denn txt_ ist definiert 
als unsigned char *txt_[20];.
Auf dem Display wird in der Zeile dann nur Buchstabensalat angezeigt.

Kann mir jemand helfen das umzusetzen oder geht das so garnicht.?

Ich möchte allerdings nicht das System neu aufsetzen, deshalb bitte kein 
anderes Menüprinzip vorschlagen.
Eher würde ich auf dynamische Texte verzichten.

Bitte habt Nachsehen mit Fehlern, ich bin da noch nicht so fit drauf.

PIC18F2585 und mikroc pro compiler.

Gruß und Danke vorab...

CL

von Stefan E. (sternst)


Lesenswert?

Du kannst zwar die Texte selber nicht ändern, aber du kannst doch 
einfach den Pointer in der Struktur auf einen anderen Text zeigen 
lassen.
1
menu[1].text = "NeuText:            ";

von C. L. (calle)


Angehängte Dateien:

Lesenswert?

Stefan E. schrieb:
> Du kannst zwar die Texte selber nicht ändern, aber du kannst doch
> einfach den Pointer in der Struktur auf einen anderen Text zeigen
> lassen.
> menu[1].text = "NeuText:            ";

Hol ruhig mal ein bisl weiter aus mit der Beschreibung, wie gesagt, ist 
Neuland.

Wenn ich einen anderen Text mit einem String übergebe, funktioniert das 
auch prinzipiell.
1
menu[1].text = "anderer Text        ";

Aber eigentlich soll sich der Text aus einem Text und einer 
Floatvariablen zusammensezten. Das hatte ich oben garnicht erwähnt.
quasi "neuer Text: 3.21".
1
    strcat(txt_," NeuText:");             // neuer Text
2
    fltToa (Blechstaerke_Name[0],txt,2);  // String mit 2 Kommastellen
3
    strcat(txt_,txt);                     // gewandelte Float Zahl dran
4
    Lcd_Cmd(_LCD_CLEAR);                  // Clear display
5
    Lcd_Out(1,1,txt_);                    // LCD Ausgabe

Der Menüeintrag ist jetzt also ein geänderter String mit Zahlen.
Wenn ich diesen einfach mal direkt aufs LCD Display ausgeben lasse, 
klappt das ja. siehe Bild.
Wenn doch alles klappt, warum geht es dann nicht so?
1
menu[1].text = *txt_;


Gruß

CL

von Felix U. (ubfx)


Lesenswert?

C. L. schrieb:
> Aber eigentlich soll sich der Text aus einem Text und einer
> Floatvariablen zusammensezten.

Dafür verwendet man sprintf.

also z.B:
1
float f = 1.0f;
2
static char menutext[30];
3
4
sprintf(menutext, "abc: %f", f);
5
menu[1].text = menutext;

von Stefan E. (sternst)


Lesenswert?

C. L. schrieb:
> Wenn doch alles klappt, warum geht es dann nicht so?
> menu[1].text = *txt_;

Weil der * hier falsch ist.

von derjaeger (Gast)


Lesenswert?

>Dafür verwendet man sprintf.

Immer snprintf verwenden:
1
snprintf(menutext, 30, "abc: %f", f);

von Felix U. (ubfx)


Lesenswert?

derjaeger schrieb:
> Immer snprintf verwenden:

Unnötig wenn man keinen userinput im formatstring hat

von Markus F. (mfro)


Lesenswert?

C. L. schrieb:
> Konstantendefinition

Ein altes Mißverständnis. const definiert in C keineswegs eine 
Konstante. Das Schlüsselwort ist lediglich das Versprechen des 
Programmierers an den Compiler, dass er nicht vor hat, auf die 
entsprechende Variable zu schreiben. Es verhindert keineswegs, dass man 
das tut (genausowenig wie restrict Pointer Aliasing verhindert - das 
ist nur das Versprechen, es nicht zu tun).

Diese Versprechen erlauben Compilern Optimierungen durchzuführen, die 
sie ohne die entsprechenden Schlüsselworte nicht durchführen könnten. 
Versprechen kann man brechen, muss dann aber - wie im richtigen Leben - 
mit den potentiellen Folgen leben.

von C. L. (calle)


Lesenswert?

Felix U. schrieb:
> C. L. schrieb:
>> Aber eigentlich soll sich der Text aus einem Text und einer
>> Floatvariablen zusammensezten.
>
> Dafür verwendet man sprintf.
>
> also z.B:
>
1
> float f = 1.0f;
2
> static char menutext[30];
3
> 
4
> sprintf(menutext, "abc: %f", f);
5
> menu[1].text = menutext;
6
>

Ok, sprintf ist eingesetzt und habe ich jetzt probiert, gibt aber eine 
"illigal pointer conversion" in der Zeile menu[1].text = menutext;
Warum gibts die Meldung, wenn doch ein sauberer String übergeben wird?

CL

von derjaeger (Gast)


Lesenswert?

>Warum gibts die Meldung, wenn doch ein sauberer String übergeben wird?

Wie wärs mal mit:
1
menu[1].text = (char*)menutext

von C. L. (calle)


Lesenswert?

derjaeger schrieb:
>>Warum gibts die Meldung, wenn doch ein sauberer String übergeben wird?
>
> Wie wärs mal mit:
>
>
1
> menu[1].text = (char*)menutext
2
>

Gemacht, ergibt aber eine "illegal pointer conversion"

:-/

von Felix U. (ubfx)


Lesenswert?

Wahrscheinlich will er, dass du nach (const char *) castest.

von derjaeger (Gast)


Lesenswert?

Welchen Compiler verwendest du? Avr-gcc?
Bei mir kompiliert dein obiger Code ohne Probleme/Warnings

von derjaeger (Gast)


Lesenswert?

>Wahrscheinlich will er, dass du nach (const char *) castest.

Ich kann den Code auch ohne Casting kompilieren (avr-gcc)

von C. L. (calle)


Lesenswert?

derjaeger schrieb:
>>Wahrscheinlich will er, dass du nach (const char *) castest.
>
> Ich kann den Code auch ohne Casting kompilieren (avr-gcc)

Ich verwende den MikroC pro for PIC V7.1.0.

Klappt das Programm denn bei Euch? Habt Ihr das ausgetestet oder eine 
Möglichkeit das zu tun?

CL

von derjaeger (Gast)


Lesenswert?

Vielleicht kann dir das weiterhelfen:

https://forum.mikroe.com/viewtopic.php?f=72&t=48004&;

>707 384 Illegal pointer conversion nokia_6610MyProject.c

>getting this error when i compile my code in mikroc compiler
>for avr,whereas when i m using avrstudio with same code it works well.

von C. L. (calle)


Lesenswert?

Das habe ich mir gerade angesehen, aber kann es nicht für mich umsetzen 
wg. mangelnem Verständnis.
Definiert habe ich const unsigned char *FontTable;
Muss ich jetzt extern const unsigned char auf die Struktur;   ???

Hä???

Weis gar nicht, was ich hier mache. Sry
Kann mir das mal jemand eben zeigen, wie ich das Prinzip auf meinen Code 
anwenden kann?

CL

von Felix U. (ubfx)


Lesenswert?

C. L. schrieb:
> Das habe ich mir gerade angesehen, aber kann es nicht für mich
> umsetzen
> wg. mangelnem Verständnis.
Der schlägt exakt das gleiche vor, wie ich einige posts weiter oben. 
Casten nach (const char *).
1
menu[1].text = (const char *) menutext;

von C. L. (calle)


Lesenswert?

> Der schlägt exakt das gleiche vor, wie ich einige posts weiter oben.
> Casten nach (const char *).
>
1
> menu[1].text = (const char *) menutext;
2
>

Ich habe das nun genau so eingegeben:
1
menu[1].text = (const unsigned char *) menutext;

..fehlerfrei compiliert aber im Display geschehen auch in der Richtigen 
Zeile Änderungen aber es stehen dort nur wilde Zeichen.
Es wird also in der richtigen Zeile (menu[1].text =) geändert aber 
scheinbar nicht richtig interpretiert.
Wir scheinen doch kurz vor dem Ziel zu sein.

Was kann das noch sein?

CL

von Felix U. (ubfx)


Lesenswert?

Wahrscheinlich hast du die Variable in die du sprintf benutzt, nicht 
static oder global gemacht, wie ich das oben geschrieben habe. Wie du 
jetzt auf das "unsigned" im cast kommst, ist mir auch schleierhaft.

von C. L. (calle)


Lesenswert?

Die daklaration ist: static char menutext[20];
Zeichen hatte ich auf 20 begrenzt weil das Display auf 20 Zeichen pro 
Zeile hat.

Dann so verwendet: sprintf(menutext,"abc: %.2f", 3.21);
3.21 als Festwert, später auch mit Float Variable.

Zugewiesen dann so: menu[1].text = (const char *) menutext;

Das unsigned hatte ich mal probiert, weil es so auch nicht ging.
Folgendes ist mir allerdings aufgefallen!
Wenn ich es so mache, wie Du es sagst, dann flackert im Display die 
Darstellung.
Wenn ich den String initialisiere bei der Definition mit
1
static char menutext[20] = {'a'};

dann ist alles gut, bis auf die wilden Zeichen, allerdings in der 
korrekten Zeile.

@ Felix U
Kannst Du das Programm mal in einen PIC18F flaschen und mit Display 
testen?
Dann würde ich Dir das mal via PN schicken.

CL

von Felix U. (ubfx)


Lesenswert?

Ich habe leider keinen PIC, aber wenn du mal deinen ganzen Code 
hochlädst, dann kann man noch weiterschauen. Versuche vielleicht auch 
nochmal eine globale Variable für den Text, ohne static, es scheint ja 
als würde der Speicherbereich mit "wilden Zeichen" überschrieben werden.

von derjaeger (Gast)


Lesenswert?

>bis auf die wilden Zeichen, allerdings in der korrekten Zeile.


Diese "wilden Zeichen" kommen wahrscheinlich, weil dein String nicht 
nullterminiert ist.

Probier mal das so:

static char menutext[20] = "a";

Gehen dann diese wilden Zeichen weg?

Oder so:
1
static char menutext[20];
2
menutext[0]='a';
3
menutext[1]=0;

von C. L. (calle)


Angehängte Dateien:

Lesenswert?

Felix U. schrieb:
> als würde der Speicherbereich mit "wilden Zeichen" überschrieben werden.

Das sieht zumindest genau so aus.


derjaeger schrieb:
> static char menutext[20] = "a";
>
> Gehen dann diese wilden Zeichen weg?

Probiert, keine Änderung.

Anbei auch das Programm.
Die wesentlichen Codezeilen befinden sich am Ende in der while Schleife.

Hinweis. Falls jemand das laufen lässt, könnte euch die Ansteuerung des 
I2C Expanders Probleme machen. Wenn er nicht vohanden ist, dann kann er 
kein ACK senden und das Programm bleibt stehen. Dann halt in der 
Initialisierung auskommentieren.

Dann bin ich mal gespannt, ob ihr noch was beitragen könnt.

Gruß
CL

Beitrag #5168162 wurde vom Autor gelöscht.
von Martin B. (martin_b97)


Lesenswert?

Hallo,

mal probiert die ganzen "const char..." strings ins flash zu legen? Ich 
hatte vor kurzem ein ähnliches Problem auf einem der neueren Tinys, 
namentlich ein Tiny816, der dann auch wirres Zeug ausgegeben hat, obwohl 
laut Compiler noch reichlich Flash und RAM verfügbar waren. Allerdings 
nicht auf LCD, sondern über USART.

Auch wenns bei dir kein AVR ist, wäre es einen Versuch wert. Bei mir war 
die Lösung, die Variablen mit "const __flash char..." zu deklarieren, 
und dann mit den entsprechenden Funktionen mit _P am Ende aufzurufen.

Grüße,
Martin

: Bearbeitet durch User
von GZ (Gast)


Lesenswert?

Also ich habe das mal bei mir nachgebildet.....

Läuft nicht..... egal was ich mache, es kommt nur Blödsinn dabei rum.

An deinem Hard/Software bundle liegt es wohl nicht.... Ich nutze den 
selben Compiler, den selben pic.

Seltsam. Wäre schöner gewesen, ich könnte dir helfen aber vielleicht hat 
jemand anderes noch einen Denkanstoß.... Würde mich auch interessieren

von C. L. (calle)


Lesenswert?

Martin B. schrieb:
> mal probiert die ganzen "const char..." strings ins flash zu legen

Das habe ich noch nicht gemacht, versuche ich. Weiss jemand wie die 
Syntax dafür ist? Muss ich mal in der Compilerdoku nachsehen.

Martin B. schrieb:
> und dann mit den entsprechenden Funktionen mit _P am Ende aufzurufen

Das verstehe ich nicht. Einfach _P daranhängen?
Woher kommt das _P?

GZ schrieb:
> Wäre schöner gewesen, ich könnte dir helfen

Weisst Du wie ich das mit dem const __flash machen soll?
Mir stellt sich die Frage, wenn das im flash liegt, wie es dann per 
Laufzeit geänder werden kann, wenn es nicht im RAM liegt.

CL

von Martin B. (martin_b97)


Lesenswert?

>> mal probiert die ganzen "const char..." strings ins flash zu legen
>
> Das habe ich noch nicht gemacht, versuche ich. Weiss jemand wie die
> Syntax dafür ist? Muss ich mal in der Compilerdoku nachsehen.

z.B. const __flash char menu_000[] = "[Hauptmenue]";

> Das verstehe ich nicht. Einfach _P daranhängen?
> Woher kommt das _P?

Ich weiß nicht, weo deine Lcd_Out() Routinen herkommen, aber villeicht 
gibt es da auch Lcd_Out_P(). Das _P ist halt so eine Namensgebung, wenn 
die Routinen (z.B. auch printf_P()) Daten aus dem Flash lesen.

> Mir stellt sich die Frage, wenn das im flash liegt, wie es dann per
> Laufzeit geänder werden kann, wenn es nicht im RAM liegt.

Es hält dich ja keiner davon ab, die konstanten Strings aus dem Flash zu 
lesen und die variablen im RAM zu haben.

Du kannst ja Lcd_Out() und Lcd_Out_P(), sofern vorhanden, auch mischen.

Grüße,
Martin

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.