Hallo,
ich schreibe an einem kleinem Tool. Dabei habe ich ein Modul implementiert, das die Eingabe von der Tastatur in einem String einliest. Durch strtok() und vorherige Vereinbarung des Delimiters wird der String zerlegt und die Teilstrings bspw. per atoi() in Integer umgewandelt.
Nun soll das aber eine allgemeingültige Funktionalität werden, die sowohl auf Integers, Floats, Strings usw. arbeiten soll. Ich kann aber nur einmal einen Datentyp für den Rückgabewert festlegen kann. Ich habe keine Polymorphie, leider! Ich will aber in ANSI-C bleiben. Wie kann ich das Problem lösen bzw. umgehen?
MfG
Carsten
Hallo,
macianer@online.de macianer@online.de (Do 01 Jun 2006 12:09:35 CEST):
Nun soll das aber eine allgemeingültige Funktionalität werden, die sowohl auf Integers, Floats, Strings usw. arbeiten soll. Ich kann aber nur einmal einen Datentyp für den Rückgabewert festlegen kann. Ich habe keine Polymorphie, leider! Ich will aber in ANSI-C bleiben. Wie kann ich das Problem lösen bzw. umgehen?
Du könntest einen eigenen Datentyp (z.B. eine union) nehmen.
#include <stdlib.h> #include <stdio.h>
typedef struct { char type; union { int i; char c; char* s; }; } value;
value reader() { value r;
r.type = 'i'; r.i = 42;
return r; }
int main(int argc, char **argv) { value v = reader();
switch (v.type) { case 'i': printf("i: %d\n", v.i); break; case 'c': printf("i: %c\n", v.c); break; case 's': printf("i: %s\n", v.s); break; }
exit(0); }
Heiko
Am 01.06.2006 um 12:34 schrieb Heiko Schlittermann:
Hallo,
macianer@online.de macianer@online.de (Do 01 Jun 2006 12:09:35 CEST):
Nun soll das aber eine allgemeingültige Funktionalität werden, die sowohl auf Integers, Floats, Strings usw. arbeiten soll. Ich kann aber nur einmal einen Datentyp für den Rückgabewert festlegen kann. Ich habe keine Polymorphie, leider! Ich will aber in ANSI-C bleiben. Wie kann ich das Problem lösen bzw. umgehen?
Du könntest einen eigenen Datentyp (z.B. eine union) nehmen.
Danke für den Tip. Ich war kurz nach der Mail auch drauf gekommen. Das Modul wird zwar eine Wahnsinnsfallunterscheidung machen, da ich den Eingabestring auch noch daraufhin untersuchen werde, ob Terme (z.B. a+b) oder sowas enthalten sind. Schade, das C kein elseif{} kennt... (Ich weiß, es gibt switch(), aber in näherer Zukunft werden Teile des Programms in Inline-Assembler geschrieben werden. Und if- else-Konstrukte sind da etwas handlicher, finde ich.)
MfG
Carsten
Carsten Friede macianer@online.de (Do 01 Jun 2006 13:27:38 CEST):
Am 01.06.2006 um 12:34 schrieb Heiko Schlittermann:
Du könntest einen eigenen Datentyp (z.B. eine union) nehmen.
Danke für den Tip. Ich war kurz nach der Mail auch drauf gekommen. Das Modul wird zwar eine Wahnsinnsfallunterscheidung machen, da ich
...
(z.B. a+b) oder sowas enthalten sind. Schade, das C kein elseif{} kennt... (Ich weiß, es gibt switch(), aber in näherer Zukunft werden Teile des Programms in Inline-Assembler geschrieben werden. Und if- else-Konstrukte sind da etwas handlicher, finde ich.)
switch() ist auch in Assembler handlich, es sind berechnete Sprünge. Und elseif gibt's:
if (..) { ... } else if (..) { ... } else if (..) { ... } else { }
Was gefällt Dir daran nicht?
Heiko
Am 01.06.2006 um 14:17 schrieb Heiko Schlittermann:
switch() ist auch in Assembler handlich, es sind berechnete Sprünge. Und elseif gibt's:
if (..) { ... } else if (..) { ... } else if (..) { ... } else { }
Was gefällt Dir daran nicht?
Ich bin begeistert! :-)
Ich war der festen Überzeugung, daß es sowas in C nicht gibt. Naja, wieder was gelernt.
Carsten Friede macianer@online.de (Do 01 Jun 2006 21:27:55 CEST):
Am 01.06.2006 um 14:17 schrieb Heiko Schlittermann:
switch() ist auch in Assembler handlich, es sind berechnete Sprünge.
Ich war der festen Überzeugung, daß es sowas in C nicht gibt. Naja, wieder was gelernt.
Es ist auch nichts anderes, als es woanders gibt, Du darfst auch in anderen Sprachen ein 'if' im 'else' haben, nur daß C erlaubt, die geschweiften Klammern wegzulassen, wenn nur genau ein Statement dem 'else' (bzw. dem 'if') folgt. Und das dem 'else' folgende 'if' ist genau ein Statement. usw. usf.
Alle 13:27, giovedì, 1. giugno 2006, Carsten Friede ha scritto:
Danke für den Tip. Ich war kurz nach der Mail auch drauf gekommen. Das Modul wird zwar eine Wahnsinnsfallunterscheidung machen, da ich den Eingabestring auch noch daraufhin untersuchen werde, ob Terme (z.B. a+b) oder sowas enthalten sind.
Warum nutzt du keinen Parsergenerator? Das sieht mir doch alles nach sehr viel Handfrickelei für nichts und wieder nichts aus. Darf man den Anwendungszweck dafür erfahren?
Josef
Am 01.06.2006 um 15:47 schrieb Josef Spillner:
Alle 13:27, giovedì, 1. giugno 2006, Carsten Friede ha scritto:
Danke für den Tip. Ich war kurz nach der Mail auch drauf gekommen. Das Modul wird zwar eine Wahnsinnsfallunterscheidung machen, da ich den Eingabestring auch noch daraufhin untersuchen werde, ob Terme (z.B. a+b) oder sowas enthalten sind.
Warum nutzt du keinen Parsergenerator? Das sieht mir doch alles nach sehr viel Handfrickelei für nichts und wieder nichts aus. Darf man den Anwendungszweck dafür erfahren?
Parsergenerator? Klingt für mich nach "Mit Kanonen auf Spatzen schiessen und treffen"... ;-)
Das Ganze Gerödel hier soll mal ein Modul (ganz in Sinne der der Wiederverwertbarkeit) werden, was mir die Funktionalität gibt Strings einzulesen und sie gezielt für den jeweiligen Kontext zu verarbeiten. Ganz speziell wird's für die Interpretation einer eigenen Kommandosprache für eine Steueranlage. --> Da würde dann ein Parser Sinn machen, das gebe ich zu. Nur leider habe ich gar keine Ahnung, wie man sowas "richtig" baut. Deswegen auch erstmal die umständliche Lösung mit String-Tokenizer und eigener Datenstruktur.
MfG
Carsten
Carsten Friede schrieb:
Das Ganze Gerödel hier soll mal ein Modul (ganz in Sinne der der Wiederverwertbarkeit) werden, was mir die Funktionalität gibt Strings einzulesen und sie gezielt für den jeweiligen Kontext zu verarbeiten. Ganz speziell wird's für die Interpretation einer eigenen Kommandosprache für eine Steueranlage. --> Da würde dann ein Parser Sinn machen, das gebe ich zu. Nur leider habe ich gar keine Ahnung, wie man sowas "richtig" baut. Deswegen auch erstmal die umständliche Lösung mit String-Tokenizer und eigener Datenstruktur.
Sieh Dir einfach mal lexx und bison an. In den Dokus sind jeweils Lösungen für einfache Taschenrechner usw. drin. Bei anderen Parsern ist das sicherlich ähnlich.
Tobias
Gottfried Staubach UNIX-Werkzeuge zur Textmusterverarbeitung Springer-Verlag
ISBN 3-540-51232-2 ISBN 0-387-51232-2
Ist kurz und verständlich geschrieben (awk, lex, yacc).
Hallo,
Nun soll das aber eine allgemeingültige Funktionalität werden, die sowohl auf Integers, Floats, Strings usw. arbeiten soll. Ich kann aber nur einmal einen Datentyp für den Rückgabewert festlegen kann. Ich habe keine Polymorphie, leider! Ich will aber in ANSI-C bleiben. Wie kann ich das Problem lösen bzw. umgehen?
Die sauberste Lösung in C sollte die Definition eines passenden Datentyps sein. Bedeutet allerdings recht viel Ballast.
#DEFINE T_INT 1 #DEFINE T_FLOAT 2 #DEFINE ...
typedef struct { int type; union { int a, float b, char* c, ....} data; } my_nice_struct;
Rückgabewert der Funktion ist dann Pointer auf einen obigen struct.
Zugriff ala
my_nice_struct x; ... switch (x.type) { case T_INT: do_something(x.data.a); break; case T_FLOAT: do_anything(x.data.b); ...
mfg, Fabian
Hallo Fabian,
Fabian Hänsel Fabian Hänsel fabtagon@gmx.de:
Nun soll das aber eine allgemeingültige Funktionalität werden, die sowohl auf Integers, Floats, Strings usw. arbeiten soll. Ich kann aber nur einmal einen Datentyp für den Rückgabewert festlegen kann. Ich habe keine Polymorphie, leider! Ich will aber in ANSI-C bleiben. Wie kann ich das Problem lösen bzw. umgehen?
Die sauberste Lösung in C sollte die Definition eines passenden Datentyps sein. Bedeutet allerdings recht viel Ballast.
#DEFINE T_INT 1 #DEFINE T_FLOAT 2 #DEFINE ...
Abgesehen davon, dass es "define" heißen müsste, ist ein enum besser, weil du dann eine Typprüfung zur Kompilierungszeit hast.
Freundlich grüßend,
Erik
Hi Namenloser,
macianer@online.de macianer@online.de:
ich schreibe an einem kleinem Tool. Dabei habe ich ein Modul implementiert, das die Eingabe von der Tastatur in einem String einliest. Durch strtok() und vorherige Vereinbarung des Delimiters wird der String zerlegt und die Teilstrings bspw. per atoi() in Integer umgewandelt.
Nun soll das aber eine allgemeingültige Funktionalität werden, die sowohl auf Integers, Floats, Strings usw. arbeiten soll. Ich kann aber nur einmal einen Datentyp für den Rückgabewert festlegen kann. Ich habe keine Polymorphie, leider! Ich will aber in ANSI-C bleiben. Wie kann ich das Problem lösen bzw. umgehen?
Ich würde dem Aufruf einen void-Pointer mitgeben, der das Ergebnis zurückliefert (Zahlenwerte sind der Wert des Pointers und bei Strings ist der Pointer die Anfangsadresse) und der Rückgabewert der Funktion (z.B. ein enum) legt fest, wie der Pointer interpretiert (gecastet) wird.
Freundlich grüßend,
Erik
Hi,
Nun soll das aber eine allgemeingültige Funktionalität werden, die sowohl auf Integers, Floats, Strings usw. arbeiten soll. Ich kann aber nur einmal einen Datentyp für den Rückgabewert festlegen kann. Ich habe keine Polymorphie, leider! Ich will aber in ANSI-C bleiben. Wie kann ich das Problem lösen bzw. umgehen?
Ich würde dem Aufruf einen void-Pointer mitgeben, der das Ergebnis zurückliefert (Zahlenwerte sind der Wert des Pointers und bei Strings ist der Pointer die Anfangsadresse) und der Rückgabewert der Funktion (z.B. ein enum) legt fest, wie der Pointer interpretiert (gecastet) wird.
Kannst du das etwas genauer erklären, ich kann mir das nicht so gut vorstellen. Danke.
MfG
Carsten
Hi,
Carsten Friede Carsten Friede macianer@online.de:
Ich würde dem Aufruf einen void-Pointer mitgeben, der das Ergebnis zurückliefert (Zahlenwerte sind der Wert des Pointers und bei Strings ist der Pointer die Anfangsadresse) und der Rückgabewert der Funktion (z.B. ein enum) legt fest, wie der Pointer interpretiert (gecastet) wird.
Kannst du das etwas genauer erklären, ich kann mir das nicht so gut vorstellen. Danke.
Hm, um die Zeit noch kodieren, mal sehen ... ;-)
typedef enum { eRT_INVALID, eRT_SHORT, eRT_LONG, eRT_CHAR, eRT_STR } TE_RT;
TE_RT reader(void *ptr) { char pInpStr[255]; TE_RT eRc = eRT_INVALID; readFromKeyboard(pInpStr); cutWithStrtok(pInpStr); eRc = decideIfShortLongCharStrAndLoadDataIntoPtr(pInpStr,ptr); return eRc; }
int main(int argc, char **argv) { void *ptr = NULL; switch (reader(ptr)) { case 'eRT_INT': printf("input: %d\n", (int)ptr); break; case 'eRT_LONG': printf("input: %ld\n",(long)ptr); break; case 'eRT_CHAR': printf("input: %c\n", (char)ptr); break; case 'eRT_STR': printf("input: %s\n", (char*)ptr); break; case 'eRT_INVALID': printf("Error\n"); break; } return 0; }
Der Inhalt des void-Pointer ist entweder ein Wert oder die Adresse des Zeichenvektors. Das Beispiel ist ungetestet.
Freundlich grüßend,
Erik
Hi,
{ case 'eRT_INT': printf("input: %d\n", (int)ptr); break; case 'eRT_LONG': printf("input: %ld\n",(long)ptr); break; case 'eRT_CHAR': printf("input: %c\n", (char)ptr); break; case 'eRT_STR': printf("input: %s\n", (char*)ptr); break; case 'eRT_INVALID': printf("Error\n"); break; }
Der Inhalt des void-Pointer ist entweder ein Wert oder die Adresse des Zeichenvektors. Das Beispiel ist ungetestet.
Da gefiel mir das mit der Union besser, da sind wenigstens keine Typecasts notwendig und Fallunterscheidung muß auch gemacht werden. Und wenn die Rückgabe der struct mißfällt, kann ja auch ein Pointer auf eine struct zurückgegeben werden.
Heiko
lug-dd@mailman.schlittermann.de