Hallo,
hier habe ich einen Codeschnipsel, den ich selbst mal irgendwo (Hier im
Forum? Leider finde ich die Stelle nicht mehr) kopiert und angepasst
habe.
int16_t(*func)(int16_t);// found <-- Was macht das???
23
func=(int16_t(*)(int16_t))pgm_read_word(&cmd->func);// get pointer
24
returnfunc(1);
25
}
26
if(DEBUG)UsartPuts("Syntax Error\n");
27
return0;
Die Funktion Execute ruft mir die entsprechende Funktion auf, die als
String übergeben wird. Das funktioniert auch so weit wunderbar.
Was mir hier aber unklar ist, habe ich oben markiert.
Jetzt wollte ich etwas ähnliches machen. Es sollen Zeilen aus einer
Konfigurationsdatei eingelesen werden und entsprechende Variablen
gesetzt werden. (Format Variable=Wert, für jede Variable eine neue
Zeile)
Dazu habe ich den Code wie folgt angepaßt:
1
typedefstruct{
2
void(*varpointer);// Pointer to the variable
3
chartext[10];// keyword
4
}keyword_t;
5
6
// default values
7
uint8Vcc_min=237;
8
uint8SleepTime=0;
9
10
// keyword array for the configuration file (pointer to the variables)
11
constkeyword_tkeywords[]PROGMEM={
12
{&SleepTime,"SLEEPTIME"},
13
{&Vcc_min,"VCC_MIN"}
14
};
15
16
17
relevanterAuschnittausderbetreffendenFunktion:
18
19
charfilechar;
20
uint8_ti;
21
constkeyword_t*key=keywords;
22
charsline[MAX_BUFFER];
23
char*vline;
24
25
while(filechar=FAT_ReadLine(file,sline,MAX_BUFFER))// read until EOL
varpointer=(int16_t(*)(int16_t))pgm_read_word(&key->varpointer);// get pointer
34
35
// replace EOL to 0x00 (use as string)
36
vline=strchr(sline,0x0D);
37
*vline=0x00;
38
// seek the "=" in the line, vline is now a string with the value after '='
39
vline++=strchr(sline,0x3D);
40
41
// set the variable of the key table to the readed value
42
*varpointer=atoi(vline);
43
44
}
varpointer sollte doch jetzt ein Pointer auf meine gesuchte Variable
sein, *varpointer somit der Inhalt.
Beim Kompilieren bekomme ich hier aber den Fehler:
error: lvalue required as left operand of assignment
Wo ist hier mein Denkfehler?
Gruß
Andreas
Du wirfst hier kunterbunt Datenzeiger und Zeiger auf Funktionen
durcheinander.
Lern in deinem C-Buch über normale Pointer und mach erst mal einen Bogen
um Funktionspointer.
Und so wie das aussieht, bist du gut beraten erst mal keine void Pointer
zu benutzen. So wie das aussieht, gibt es dazu auch keinen Grund.
Hallo Karl-Heinz,
daß das im Original Funktionszeiger sind, ist mir schon klar. Die Basics
von Pointern habe ich schon verstanden. Mir fehlt halt die Übung in C.
Es sollen jetzt aber Zeiger auf meine Variablen sein, die ich vorher
deklariert habe.
Was macht denn jetzt genau int16_t (*func)(int16_t)?
Dabei wird scheibar auch die Variable func deklariert. Aber verstehen
tue ich diese Zeile nicht.
Gruß
Andreas
sind Zeiger auf Funktionen. Im Original werden keine Werte
abgespeichert, sondern abhängig vom Text Funktionen aufgerufen. Das ist
was völlig anderes. Das ist schon etwas aus der gehobeneren Kategorie
der Programmierung.
func ist ein Zeiger auf eine Funktion und diese Funktion will einen
int16_t als Argument haben und liefert als Returnwert einen int16_t.
Kannst du mir erklären, warum du hier
1
vline++=strchr(sline,0x3D);
0x3D schreibst? Warum nicht einfach
1
vline++=strchr(sline,'=');
Wäre das zu einfach? Zu Lesbar? Zu wenige Möglichkeiten Fehler zu
machen? Nach dem Motto: "Es war schwer zu schreiben, also soll es auch
schwer zu lesen sein!"
Im übrigen hat die ganze Anweisung undefiniertes Verhalten.
1
vline=strchr(sline,'=');
2
vline++;
Und abfragen, ob '=' überhaupt gefunden wurde, sollte man dann auch
noch.
1
vline=strchr(sline,'=');
2
if(vline!=NULL)
3
{
4
vline++;
5
*varpointer=atoi(vline);
6
}
Das EOL entfernen kannst du dir hingegen sparen. atoi hört sowieso mit
der Konvertierung auf, sobald es auf das erste Zeichen stösst, welches
nicht mehr zu einer Zahl gehören kann. Solange dein String sauber
aufgebaut ist, mit einem \0 Zeichen als letztes Zeichen (welches ein
String sowieso immer haben sollte, denn sonst ist es kein String), kann
dir da also gar nichts passieren. Aber wenn du schon ersetzen willst,
dann bitte auch immer prüfen, ob ein gesuchtes Zeichen auch wirklich
gefunden wurde! Alles andere ist nämlich ein Spiel mit dem Feuer
1
// replace EOL to 0x00 (use as string)
2
vline=strchr(sline,0x0D);
3
if(vline!=NULL)
4
*vline=0x00;
Die ganze Schleife kann man im übrigen auch ohne von hinten durch die
Brust ins Auge programmieren. Zum einen kann man durch umdrehen der
strcasecmp_P Abfrage den continue wegbringen, zum anderen könntest du
dich mit dir einigen, ob du jetzt über einen Index zugreifst, oder doch
einen Pointer weiterzählen willst.
Hallo Karl-Heinz,
Danke für die Tips. Ich gehe das jetzt mal alles durch. Ich habe vor
einigen Jahren mal etwas in C programmiert. Mir fehlt da einfach die
Übung.
Das Ende des Strings habe ich nicht beachtet, da der String ja aus einer
Datei ausgelesen wird. Spätestes beim EOF ist ja das Ende des Strings.
Aber Du hast recht, ich werde das etwas sauberer programmieren.
Kannst Du diese Zeile (int16_t (*func)(int16_t);) mal etwas erläutern?
Daß *func ein Pointer auf eine Funktion ist, habe ich schon verstanden.
Das ist im Datentyp der Struktur ja so definiert. Ist das nur eine
Deklaration für func als Funktionspointer? Wenn ja, warum definiert man
das nicht am Anfang der Funktion selbst?
Gruß
Andreas
Andreas B. schrieb:> Kannst Du diese Zeile (int16_t (*func)(int16_t);) mal etwas erläutern?
1
% cdecl
2
Type `help' or `?' for help
3
explain unsigned short (*fp)(unsigned short)
4
declare fp as pointer to function (unsigned short) returning unsigned short
(Ich habe mal "fp" statt "func" benutzt, da "func" bei cdecl ein
Schlüsselwort ist. Die Zeile mit "explain" ist meine Eingabe, die mit
"declare" die Ausgabe von cdecl.)
Hallo Jörg,
Danke Dir!
Also doch einen Delaration. Es hatte mich nur irritiert, daß diese
Deklaration im Ursprungscode mitten im Code stand.
Gruß
Andreas
Andreas B. schrieb:> Es hatte mich nur irritiert, daß diese> Deklaration im Ursprungscode mitten im Code stand.
In C99 sind Variablendefinitionen mitten im Code zulässig (und in C++
sowieso).
Am Anfang eines Blocks (eines in {} stehenden Abschnittes, also auch in
einem if-Statement oder in einer for-Schleife o.ä.) sind sie das in C
aber schon immer, auch wenn das hier nicht der Fall ist. o.g. Code lässt
sich also nur von einem C99-toleranten Compiler übersetzen.
Ob man Variablen so definieren möchte, ist in erster Linie eine
stilistische Frage; es gibt Leute, die der Ansicht sind, Variablen
sollten so spät wie möglich definiert werden, und es gibt Leute, die der
Ansicht sind, daß alle in einer Funktion verwendeten Variablen an deren
Anfang definiert werden sollten. Letzteres hilft beim Quelltextlesen den
Stackbedarf einzuschätzen.