Forum: Compiler & IDEs AVR GCC - Einfache Stringmanipulation


von Peter Rachow (Gast)


Lesenswert?

Hallo zusammen,

der folgende Codeschnipsel stammt aus der Frequenzaufbereitung eines 
Amateurfunkgerätes, das ich gerade baue. Verwaltet werden damit einzelne 
virtuelle Oszillatoren, deren Frequenz dann jeweils in ein DDS 
eingelesen wird.
1
void show_vfo(int vfo_num)
2
{
3
    char *vfo_str = "VFO  ";
4
5
    *(vfo_str + 4) = vfo_num + 65;
6
    lcd_put_string(x0 + 2, y0 + 2, vfo_str, 1, DARKBROWN, LIGHTGREEN);
7
}

Angezeigt werden soll ein String "VFO X", wobei der Buchstabe X durch 
einen beliebigen Buchstaben ersetzt werden soll. Also "VFO A", "VFO B" 
etc. etc. Die übergebenen Zahlenwerte in vfo_num reichen von 0 bis 12. 
Analog dazu soll der Kennbuchstabe des Frequenzspeichers auf der 5. 
Stelle des String landen.

Wenn ich den Code in meinem alten "Turbo C"-Compiler teste, funktioniert 
es. Beim GCC für AVR (WINAVR 20100110) aber nicht. Das Ganze als Array 
ginge zwar auch, will ich aber nicht. Den Buchstaben separat hinter 
"VFO" schreiben wäre auch eine Alternative, aber ich will wissen, warum 
das hier nicht tut.

Ich stehe gerade mal heftig auf dem Schlauch. Hilft mir jemand runter? 
;-)

Viele Grüße

Peter
(DK7IH)

: Verschoben durch Moderator
von Peter II (Gast)


Lesenswert?

Peter Rachow schrieb:
> Ich stehe gerade mal heftig auf dem Schlauch. Hilft mir jemand runter?
> ;-)

sollte gehen, sicher das der Fehler nicht woanders ist?

Man kann es auch lesbar schreiben
1
vfo_str[4] = vfo_num + 'A';
;

von bundesNetzAgent (Gast)


Lesenswert?

Braucht lcd_put_string einen nullterminierten String ?
0 1 2 3 4 5
V F 0 _ X /0

von Peter II (Gast)


Lesenswert?

bundesNetzAgent schrieb:
> Braucht lcd_put_string einen nullterminierten String ?
> 0 1 2 3 4 5
> V F 0 _ X /0

hat er doch.

von Klaus (Gast)


Lesenswert?

Mit der Definition und Initialisierung
1
char *vfo_str = "VFO  ";


reservierst Du auf dem Stack nur 5 Zeichen (einschl. dem 
Nullterminator).
Garantiert ist jedenfalls nur diese Länge - mehr ist ja eigentlich auch 
nicht nötig. Das Du da noch Zeichen anfügen willst, weiß der Compiler 
nicht.

von Klaus (Gast)


Lesenswert?

Ooops. Sorry.

Du reservierst nur einen Zeiger auf dem Stack der auf einen Bereich, der 
jedoch nur für 5 Zeichen ausgelegt sein muss, zeigt. Wenn Du da was 
anhängst, kann das schiefgehen. Geht es hier wohl auch.

von Peter II (Gast)


Lesenswert?

Klaus schrieb:
> Mit der Definition und Initialisierung
> char *vfo_str = "VFO  ";
>
> reservierst Du auf dem Stack nur 5 Zeichen (einschl. dem
> Nullterminator).

ich zähle 6 Zeichen (das sind 2 Leerzeichen!)

von Peter II (Gast)


Lesenswert?

das Problem sehe ich darin, das man die Daten nicht mainipulieren darf.

teste mal mit:
1
void show_vfo(int vfo_num)
2
{
3
    char vfo_str[] = "VFO  ";
4
    vfo_str[4] = vfo_num + 'A';
5
    lcd_put_string(x0 + 2, y0 + 2, vfo_str, 1, DARKBROWN, LIGHTGREEN);
6
}

beim PC können sie durchaus im Read-Only Ram liegen. Meist wird es zwar 
gehen aber zulässig dürfte es nicht sein.

von Mac (Gast)


Lesenswert?

1
char *vfo_str = "VFO  ";

deklariert einen Pointer auf ein (u.u. nicht beschreibbares 
String-Literal)

Probier stattdessen mal:
1
char vfo_str[] = "VFO  ";

Dies deklariert einen beschreibbaren Array, der mit "VFO  " 
initialisiert wird.

von Klaus (Gast)


Lesenswert?

Nochmal oops.

Wie ich gerade sehe, habe ich mich verzählt. Es sind 6 Zeichen.

Was heisst, denn "es funktioniert nicht"?

von bundesNetzAgent (Gast)


Lesenswert?

1
void show_vfo(int vfo_num)
2
{
3
    char vfo_str[] = "VFO  ";
4
5
    vfo_str[4] = vfo_num + 'A';
6
    //lcd_put_string(x0 + 2, y0 + 2, vfo_str, 1, DARKBROWN, LIGHTGREEN);
7
    puts(vfo_str);
8
}

Pointerversion macht auch PC Probleme.

von Klaus (Gast)


Lesenswert?

Mac hat des Pudels Kern abgeschossen. Der Punkt ist, dass der Zeiger per 
Definition nicht zwingend auf einen beschreibbaren Bereich zeigt.

Nochmal Sorry. Ich war wohl unaufmerksam.

von Peter Rachow (Gast)


Lesenswert?

Hi zusammen, danke für Eure zahlreichen Rückmeldungen und die 
Erklärungen. Dann mache ich das mit dem Array.

Viele Grüße

Peter

von Falk B. (falk)


Lesenswert?

@ Peter Rachow (Gast)

>Hi zusammen, danke für Eure zahlreichen Rückmeldungen und die
>Erklärungen. Dann mache ich das mit dem Array.

Was spricht dagegen? Weil 6 Bytes auf dem Stack angelegt werden?
Was geht denn auf dem AVR gcc nicht? Kommen kryptische Zeichen raus?
Denn so oder so muss der avr gcc den String im RAM anlegen, im Flash 
geht ja nicht. Also muss auch eine Manipulation des Strings möglich 
sein.

von Klaus (Gast)


Lesenswert?

Ich fürchte Falks Einwand ist tatsächlich maßgeblich.

Beitrag "Re: Lifetime String Literal in C"

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Forum: Projekte & Code
Hier könnt ihr eure Projekte, Schaltungen oder Codeschnipsel vorstellen 
und diskutieren. Bitte hier keine Fragen posten!

von Tcf K. (tcfkao)


Lesenswert?

*(vfo_str + 4) = vfo_num + 65;

Fehlt da nicht ein cast auf char?

Also:

(char *)(vfo_str + 4) = (char)vfo_num + 65;

Ohne handelt der Compiler das als int und schreibt das upper null byte 
des Int an Stelle wo das Char hin soll.

Meinung?

von Peter II (Gast)


Lesenswert?

Tcf K. schrieb:
> Fehlt da nicht ein cast auf char?

nein.

von Karl H. (kbuchegg)


Lesenswert?

Tcf K. schrieb:

> Meinung?


C Buch rausholen und nochmal nachlesen, wie Pointer-Datentypen und das 
Verhalten bei Dereferenzierung zusammenhängen.

von Karl H. (kbuchegg)


Lesenswert?

Peter Rachow schrieb:

> aber ich will wissen, warum
> das hier nicht tut.

Weil dein Pointer auf ein String-Literal zeigt und das per Definition 
für dich unberührbar ist.
Korrekt würdest du übrigens schreiben
1
    const char *vfo_str = "VFO  ";
womit sich dann auch der Rest erübrigt, denn dann würde dir der Compiler 
auf die Finger klopfen, wenn du versuchst einen char davon zu verändern.
Gewöhn dir an const korrekt zu arbeiten.

: Bearbeitet durch User
von Tcf K. (tcfkao)


Lesenswert?

Ja ja, schon gut.
Trotzdem, ist das nicht Performence hemmend weil vfo_str[] bei jedem 
Aufruf von show_vfo() auf dem Stack erzeugt (kopiert) werden muss? So 
kenne ich es aus der x86-Welt.

Wäre ein static vfo_str[] hier nicht besser? Er ändert ja sowieso immer 
nur ein Byte.

von Karl H. (kbuchegg)


Lesenswert?

Tcf K. schrieb:

> Wäre ein static vfo_str[] hier nicht besser? Er ändert ja sowieso immer
> nur ein Byte.

Kann man machen.
Auch wenn du den Unterschied nicht bemerken wirst. Das Ausgeben auf dem 
LCD wird ein Vielfaches der Zeit der Kopieraktion benötigen.

-> Wenn du optimierst, dann optimier dort wo es Sinn macht.

: Bearbeitet durch User
von Tcf K. (tcfkao)


Lesenswert?

Es geht um das Prinzip... ein dilettantischer Kollege hat mal eine 
CRC-Routine copy&pasted, bei der er stolz die CRC-Tabelle in den 
Funktionsrumpf kopiert hatte... ohne static davor! ;)

Ein anderer (eigentlicher Programmierer) hatte bei einer Funktion einen 
Pointer auf eine lokale Variable der Funktion retourniert...

von guest (Gast)


Lesenswert?

Das da mit einem 'alten "Turbo C"-Compiler' funktioniert, wundert mich 
nicht. Mit dem Compiler aus MS VS6 gehts auch noch, mit dem aus VS2005 
(oder wars doch erst VS2008?) geht es nicht mehr, da gibt es dann eine 
'access violation' zur Laufzeit.

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.