Hallo Forum!
Ich bin mal wieder am Verzweifeln mit C. Ich habe ein Problem mit der
Übergabe by reference. Die Funktion g_printc gibt ein Zeichen auf meinem
LCD aus. Das auszugebende Zeichen wird per Zeiger von test() übergeben
(*ichar). Nur leider funktioniert das nicht. Ich habe schon versucht mit
static test() und volatile... Funktioniert alles nicht und ich weiß
nicht warum. Könnte da bitte mal jemand drüberschauen? Warscheinlich
sehe ich den Baum vor lauter Wäldern nicht und es ist ein saudummer
Fehler.
Die Übergabe von "test" ist soweit korrekt.
Deine Funktion erwartet einen Pointer (char *ichar), Du übergibst ihr
beim Aufruf die Adresse von "test" (g_printc(5, 5, 0, &test))
Ist zwar vollkommen unklar, was das soll (Du könntest Deinen einzelnen
char auch direkt als Wert übergeben), aber korrekt ist es trotzdem.
Woran machst Du fest, daß "das nicht funktioniert"?
Könnte es sein, daß Deine Zugriffe auf Deine Zeichentabelle nicht
funktionieren, weil Du PROGMEM und normale Speicherzugriffe mischt?
M. M. schrieb:> Das auszugebende Zeichen wird per Zeiger von test() übergeben> (*ichar).
Warum über Zeiger?
> Nur leider funktioniert das nicht.
Doch, das funktioniert.
Das Problem ist nicht der Zeiger von ichar.
Rufus Τ. F. schrieb:> Ist zwar vollkommen unklar, was das soll (Du könntest Deinen einzelnen> char auch direkt als Wert übergeben), aber korrekt ist es trotzdem.
Ich mach eine zweite Funktion printf, die bekommt einen Zeiger auf ein
String-Array. Die druckt dann die einzelnen Zeichen eben mit dem printc.
Ich meine das dies effizienter ist als die Variablen zu kopieren.
> Woran machst Du fest, daß "das nicht funktioniert"?
Wenn ich in die Funktion printc nicht den Zeiger verwende, sondern eine
Variable erstelle, in diesem Fall mit char testvariable=1;, dann wird
das richtige Zeichen ausgegeben.
> Könnte es sein, daß Deine Zugriffe auf Deine Zeichentabelle nicht> funktionieren, weil Du PROGMEM und normale Speicherzugriffe mischt?
Wie meinst du das? Ist die Vorgehensweise korrekt:
const uint8_t a PROGMEM = 1;
uint8_t test;
test=a;
M. M. schrieb:> Die druckt dann die einzelnen Zeichen eben mit dem printc.> Ich meine das dies effizienter ist als die Variablen zu kopieren.
Da täuscht du dich.
Ein Zeiger braucht i.A. mehr Speicher als ein Byte.
Und somit müssen mehr Daten kopiert werden als bei der direkten
Übergabe.
Das Problem ist dann auch nicht ichar sondern charflash.
M. M. schrieb:> void g_printc(uint8_t x, uint8_t y, uint8_t font, char *ichar){> switch(font){> case 0: ;
char test2=1;
char *test3=&test2;
> char test=*test3;> uint8_t *charflash=font0+test;> g_crect(x-1, y-1, x+3, y+5);> for(uint8_t iy=0; iy<4; ++iy){> if(*charflash&(1<<iy))> g_point(x, y+iy);> }> [...]
Hier funktioniert es wie gewünscht, damit ihr wisst was ich meine. Liegt
es vielleicht an dem switch? Ist es ein Bug von AVR Studio?
Dirk B. schrieb:> Das Problem ist dann auch nicht ichar sondern charflash.
Das wäre dann hiermit wiederlegt, oder sehe ich das falsch?
So leicht kannst du den Compiler auch nicht verwirren, der macht ein
char test=1;
daraus.
Geht das denn, wenn du ichar nicht als Zeiger definierst?
Du kannst dich mit den Funktionen durchaus an der Standardbibliothek
orientieren: printf und putc
Hat zwar nichts mit dem Problem zu tun, aber:
> case 0: ;> case 1: ;> case 2: ;
gibt es einen Grund für die (sinnfreien) Semikola? Die tun zwar nicht
weh, aber extra Punkte bringen sie auch nicht.
M. M. schrieb:> Ist es ein Bug von AVR Studio?
Wenn dann wäre es ein Bug im Compiler (und nicht in der IDE), also dem
GCC, und das ist (wenn auch nicht ganz ausgeschlossen) eher
unwahrscheinlich.
Such mal hier im Forum nach Bug und GCC. Fast jeder behauptet erstmal,
das muss ein Bug im Compiler sein,... und praktisch jedes Mal stellt
sich raus, das es doch kein Bug im GCC ist.
Mit welchen Compiler flags compilierst du denn? Kann es vielleicht sein,
das der Compiler da was wegoptimiert?
M. M. schrieb:> Das wäre dann hiermit wiederlegt, oder sehe ich das falsch?
Da der Wert von test in der Funktion auf 1 festgelegt ist, kann der
Compiler ganz anders Optimieren.
Er kann *charflash komplett durch 240 ersetzen.
Kaj G. schrieb:> Hat zwar nichts mit dem Problem zu tun, aber:>> case 0: ;>> case 1: ;>> case 2: ;> gibt es einen Grund für die (sinnfreien) Semikola? Die tun zwar nicht> weh, aber extra Punkte bringen sie auch nicht.
Das dachte ich auch zuerst, aber die sind tatsächlich notwendig. Der
C-Standard sagt nach einem case: darf keine Variable initialisiert
werden.
> M. M. schrieb:>> Ist es ein Bug von AVR Studio?> Wenn dann wäre es ein Bug im Compiler (und nicht in der IDE), also dem> GCC, und das ist (wenn auch nicht ganz ausgeschlossen) eher> unwahrscheinlich.> Such mal hier im Forum nach Bug und GCC. Fast jeder behauptet erstmal,> das muss ein Bug im Compiler sein,... und praktisch jedes Mal stellt> sich raus, das es doch kein Bug im GCC ist.
Ja klar im Compiler. Ich weiß garnicht das AVR-Studio gcc nutzt. Ehrlich
gesagt kann ich es mir auch nicht vorstellen, aber an was liegt es dann?
> Mit welchen Compiler flags compilierst du denn? Kann es vielleicht sein,> das der Compiler da was wegoptimiert?
Mit den Standardeinstellungen.
Dirk B. schrieb:> Dirk B. schrieb:>> Er kann *charflash komplett durch 240 ersetzen.>> Dirk B. schrieb:>> Das Problem ist dann auch nicht ichar sondern charflash.
Dann dürfte es doch trotzdem keinen Unterschied geben, die Optimierung
ist ja in dem Fall in Ordnung.
DAs habe ich noch vergessen zu zitieren:
Rufus Τ. F. schrieb:> Könnte es sein, daß Deine Zugriffe auf Deine Zeichentabelle nicht> funktionieren, weil Du PROGMEM und normale Speicherzugriffe mischt?
M. M. schrieb:> Funktioniert:void g_printc(uint8_t x, uint8_t y, uint8_t font, char
...
> Funktioniert nicht:
Ist ganz schön was du da schreibst, aber in beiden Beispielen wird ichar
nicht verwendet... aber vielleicht bin ich auch einfach nur blind.
Kaj G. schrieb:> M. M. schrieb:>> Funktioniert:void g_printc(uint8_t x, uint8_t y, uint8_t font, char> ...>> Funktioniert nicht:> Ist ganz schön was du da schreibst, aber in beiden Beispielen wird ichar> nicht verwendet... aber vielleicht bin ich auch einfach nur blind.
Ahh du hast recht! Also nochmal richtig:
Funktioniert:
M. M. schrieb:>> gibt es einen Grund für die (sinnfreien) Semikola? Die tun zwar nicht>> weh, aber extra Punkte bringen sie auch nicht.>> Das dachte ich auch zuerst, aber die sind tatsächlich notwendig. Der> C-Standard sagt nach einem case: darf keine Variable initialisiert> werden.
Aua. Da hilft auch kein Semikolon. Wenn hier neue Variablen nötig sind,
beginnt man einen neuen Block - d.h. einen von geschweiften Klammern
umschlossenen Abschnitt.
Natürlich nur, wenn es tatsächlich nötig ist, hier neue Variablen zu
deklarieren, sonst sind sie überflüssig.
Rufus Τ. F. schrieb:> M. M. schrieb:>>> gibt es einen Grund für die (sinnfreien) Semikola? Die tun zwar nicht>>> weh, aber extra Punkte bringen sie auch nicht.>>>> Das dachte ich auch zuerst, aber die sind tatsächlich notwendig. Der>> C-Standard sagt nach einem case: darf keine Variable initialisiert>> werden.>> Aua. Da hilft auch kein Semikolon. Wenn hier neue Variablen nötig sind,> beginnt man einen neuen Block - d.h. einen von geschweiften Klammern> umschlossenen Abschnitt.>> Natürlich nur, wenn es tatsächlich nötig ist, hier neue Variablen zu> deklarieren, sonst sind sie überflüssig.http://stackoverflow.com/questions/92396/why-cant-variables-be-declared-in-a-switch-statement
In deinem Beispiel wenöglichst du dem Compiler alle Zwischenvariablen
sowiet wegzuoptimieren, bis er beim eigentlichen Zugriff auf charflash
noch immer die Information da hat, dass es sich da um einen Zugriff ins
Flash handelt.
In deinem 'funktioniert nicht' Beispiel kann der Compiler diesen weg
aber nicht gehen, weil ihm der Wert für ichar nicht bekannt ist.
Wenn du auf Dinge zugreifen willst, die due mittels PROGMEM ins Flash
legst, dann müssen die Zugriffe anders sein. Du brauchst dazu die
pgm_read Funktionen
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Flash_mit_PROGMEM_und_pgm_read
Da liegt dein Problem.
das vermeidet dann Probleme mit dem Scope, zeigt an (und garantiert),
dass diese Variable nur in diesem case verwendet werden kann und der
Block ist auch ein Hinweis an zukünftige Programmier-Generationen, dass
hier in diesem case irgendetwas 'Aussergwöhnliches' passiert.
Das Thema lautet "defensives programmieren".