Hallo,
ich suche in C die Möglichkeit einem Funktionspointer eine variable
Anzahl von Argumenten zu übergeben - scheitere aber daran, was mich
letzte Nacht den Schlaf geraubt hat!!!
Idealerweise haben hierbei die Argumente auch verschiedene
Variablentypen :-/
Kann mir jemand einen Tip oder ein Beispiel hierfür geben, damit ich die
nächste Nacht nicht vor Problemen, sondern vor Realisierungen sitze?
Vielen Dank
Markus, der Kaffee-Säufer schrieb:> Hallo,>> ich suche in C die Möglichkeit einem Funktionspointer eine variable> Anzahl von Argumenten zu übergeben - scheitere aber daran, was mich> letzte Nacht den Schlaf geraubt hat!!!>> Idealerweise haben hierbei die Argumente auch verschiedene> Variablentypen :-/
kriegst du es denn ohne Funktionspointer hin?
Also eine Funktion zu machen, die variadisch ihre Argumente übernimmt?
Mal ein vereinfachter Ansatz zum Nachdenken:
Es ist total egal, was, wie viel und warum du an eine Funktion
übergibst. Das geht in C so gut, weil der Aufrufer dafür verantwortlich
ist:
- erst alle Argumente auf den Stack zu legen,
- die Funktion aufzurufen und anschließend
- alle Argumente wieder vom Stack zu nehmen.
Die Prototypen haben sozusagen formellen Charakter.
Deshalb funktionieren z.B. auch Funktionen mit leerer Parameterliste
noch (alter K&R-Stil) -- eben weil es egal ist, was und wie viel
mitkommt. Schlimmstenfalls liest die aufgerufene Funktion eben zu viel
und läuft in einen Zugriffsfehler oder solcherlei.
Sven P. schrieb:> Es ist total egal, was, wie viel und warum du an eine Funktion> übergibst. Das geht in C so gut, weil der Aufrufer dafür verantwortlich> ist:> - erst alle Argumente auf den Stack zu legen,> - die Funktion aufzurufen und anschließend> - alle Argumente wieder vom Stack zu nehmen.
Das mag bei vielen Compilern faktisch so sein, aber "in C" wird über die
Art, wie Argumente übergeben werden, kein Wort verloren.
> Die Prototypen haben sozusagen formellen Charakter.>> Deshalb funktionieren z.B. auch Funktionen mit leerer Parameterliste> noch (alter K&R-Stil) -- eben weil es egal ist, was und wie viel> mitkommt.
Nein. Aufrufer und aufgerufene Funktion müssen sich einig darüber sein,
was übergeben wird. Wenn die Paramterliste beim Aufruf nicht explizit
bekannt ist, generiert der Compiler eben eine implizite Liste, die er
aus den übergebenen Argumenten ermittelt. Er vertraut dann einfach
darauf, daß die stimmt, weil er keine Möglichkeit hat, es zu überprüfen.
Das hat aber nichts damit zu tun, wer für was zuständig ist oder wie die
Argumente dann übergeben werden.
> Schlimmstenfalls liest die aufgerufene Funktion eben zu viel und läuft in> einen Zugriffsfehler oder solcherlei.
Würde dir denn was schlimmeres einfallen, das noch passieren könnte?
Rolf Magnus schrieb:> Das mag bei vielen Compilern faktisch so sein, aber "in C" wird über die> Art, wie Argumente übergeben werden, kein Wort verloren.
Das ist richtig. Gerade deshalb ist die von mir beschriebene
Aufrufkonvention ja auch als 'cdecl' bekannt...
Hätte ich aber eindeutiger formulieren sollen, wohl wahr.
> Nein. Aufrufer und aufgerufene Funktion müssen sich einig darüber sein,> was übergeben wird. Wenn die Paramterliste beim Aufruf nicht explizit> bekannt ist, generiert der Compiler eben eine implizite Liste, die er> aus den übergebenen Argumenten ermittelt. Er vertraut dann einfach> darauf, daß die stimmt, weil er keine Möglichkeit hat, es zu überprüfen.
Ja. Und wo sind sich Aufrufer und Aufgerufener nun einig? Ich würde
sagen, einzig in der Aufrufkonvention.
> Das hat aber nichts damit zu tun, wer für was zuständig ist oder wie die> Argumente dann übergeben werden.
Sondern?
>> Schlimmstenfalls liest die aufgerufene Funktion eben zu viel und läuft in>> einen Zugriffsfehler oder solcherlei.>> Würde dir denn was schlimmeres einfallen, das noch passieren könnte?
Nein, was Schlimmeres, als auf verbotenen Speicher zuzugreifen fällt mir
nicht ein. Es sei dir aber gerne überlassen, dir sämtliche
Nebenwirkungen auszumalen, die so ein Zugriff etwa in Siemens-SPS haben
könnte.
Sven P. schrieb:>> Nein. Aufrufer und aufgerufene Funktion müssen sich einig darüber sein,>> was übergeben wird. Wenn die Paramterliste beim Aufruf nicht explizit>> bekannt ist, generiert der Compiler eben eine implizite Liste, die er>> aus den übergebenen Argumenten ermittelt. Er vertraut dann einfach>> darauf, daß die stimmt, weil er keine Möglichkeit hat, es zu überprüfen.>> Ja. Und wo sind sich Aufrufer und Aufgerufener nun einig? Ich würde> sagen, einzig in der Aufrufkonvention.
Natürlich, aber die muß nicht so aussehen, wie du sie beschrieben hast.
Sie ist im Prinzip beliebig, solange sie nur auf beiden Seiten gleich
ist.
Du hast oben drei Regeln erwähnt und behauptet, daß es nur aufgrund
dieser möglich sei, Funktionsdeklarationen ohne explizite Parameterliste
zu haben.
Diese Regeln sind aber keine C-Regeln, und die Deklarationen würden auch
ohne sie funktionieren. Deshalb hat Existenz dieser Art der Deklaration
nichts damit zu tun, wer den Stack aufräumt.
>> Das hat aber nichts damit zu tun, wer für was zuständig ist oder wie die>> Argumente dann übergeben werden.> Sondern?
Wie ich schon schrieb, damit, ob der Compiler prüfen kann, ob der Aufruf
korrekt ist.
>>> Schlimmstenfalls liest die aufgerufene Funktion eben zu viel und läuft>>> in einen Zugriffsfehler oder solcherlei.>>>> Würde dir denn was schlimmeres einfallen, das noch passieren könnte?> Nein, was Schlimmeres, als auf verbotenen Speicher zuzugreifen fällt mir> nicht ein.
Vielleicht hab ich's ja falsch verstanden, aber deine Aussage klang, als
sei das ja nicht weiter tragisch.
Ach so siehst du das.
Ich schrieb doch:
> Mal ein vereinfachter Ansatz zum Nachdenken:
Die Ausführungen sind vereinfacht, hamwa ja jetzt festgestellt. Wenn man
sie aber durchgeht, kommt man jedenfalls zum Ergebnis:
Eine variable Anzahl von Argumenten funktioniert beim Funktionszeiger
genauso, wie bei fest verdrahteten Funktionen.
Mehr wollte ich eigentlich nicht sagen, nur sollte es etwas anschaulich
werden. Mag sein, dass andere Compiler andere Konventionen verwenden,
alle führen aber auf diese Erkenntnis :-)
Hallo, da bin ich wieder!
Ich habe bei mir den Fall, das ich 0 bis 3 Argumente übergeben
will/muss.
Ich denke ich schreibe mir einen kleinen Parser, der überprüft, wie
viele Argumente anstehen und schreibe halt entsprechende Routinen die
diese dann via Switch-Anweisung aufrufen. -Ich denke das wird der
einfachste Weg sein.
Auch werde ich mal versuchen, eine Art Lookup zu schreiben. Hab ja noch
Wochenende - da kann ich ja noch einiges ausprobieren ;-)
Aber vielen Dank soweit!
Markus, der Kaffee-Säufer schrieb:> Hallo, da bin ich wieder!>> Ich habe bei mir den Fall, das ich 0 bis 3 Argumente übergeben> will/muss.
0 geht sowieso nicht.
Jede variadische Funktion muss mindestens 1 Argument haben, welches dazu
dient die Datentypen der restlichen (für die aufgerufene Funktion)
unbekannten Argumente zu identifizieren. Überleg einfach mal, warum man
bei einem printf alles weglassen kann, bis auf den Formatstring und
warum wohl der Protoyp für printf so
1
intprintf(constchar*,...);
aussieht und der Formatstring nicht optional ist.
> Ich denke ich schreibe mir einen kleinen Parser, der überprüft, wie> viele Argumente anstehen und schreibe halt entsprechende Routinen die> diese dann via Switch-Anweisung aufrufen. -Ich denke das wird der> einfachste Weg sein.
Schau dir einfach an, wie die Argumente an main() übergeben werden. Man
muss nicht für alles das Rad neu erfinden, manchmal reicht es auch, wenn
man sich ansieht, wie das andere Sprachelemente machen.
an die parameter kommt man ganz normal über die argumentliste...
aber interessant das mache compiler wirklich meckern. Ist mir noch nicht
passiert, sry.
Ich finde den Parameter persönlich aber auch unnötig am anfang.
Eine VariableArgumentList basiert auf der Übergabe eines Pointers auf
eine Pointerliste und zusätzlich noch natürlich die Listengröße. Die
Typen in der Argumentliste sind nicht fest definiert. Auch nicht durch
den ersten parameter (man übergibt bei printf char* und hinten kommen
int, double und sonstiger unfug)
ISO C.
Naja. :-)
@Klaus Wachtler
void t(...)
{
printf( ... ); // alles ausgeben
}
wie kommt man darauf, das printf(...) so funktioniert?? Geschweigedenn
der zugriff und weitergabe von varArgs? Sehr fundiert.
Also wer Beispiele bringt die syntaktisch gar niht funktionieren können,
soll sich nicht beschweren, dass es nicht funktionert :-/
Ich geb zu, mein compiler ist wohl nicht ISO konform.. aber welcher ist
das schon heutzutage noch ;-) Jeder hat doch seine eigenen
erweiterungen.. aber is schon ok :-) Ordentlicher code muss einen
dummyparameter haben - verstanden
DerAlbi schrieb:> an die parameter kommt man ganz normal über die argumentliste...
Und was übergibst du als zweites Argument an va_start?
DerAlbi schrieb:> Ist mir noch nicht passiert, sry.
Vermutlich arbeitest du noch im historischen pre-ANSI-C-Modus aus den
Achtzigern des letzten Jahrhunderts.
Ach, noch wasS:
DerAlbi schrieb:> Ordentlicher code muss einen dummyparameter haben - verstanden
Woran erkennt die aufgerufene Funktion denn ohne den "Dummyparameter"
eigentlich, daß gar keine Argumente kommen? Ähnlich wie bei Arrays
braucht man doch auch bei der variablen Parameterliste immer entweder
einen zusätzlichen Wert, der die Anzahl angibt oder irgendeinen
Ende-Marker, und beides bedeutet zwangsläufig, daß man auf jeden Fall
mindestens ein Argument übergeben muß.
DerAlbi schrieb:> @Klaus Wachtler>> void t(...)> {> printf( ... ); // alles ausgeben> }>> wie kommt man darauf, das printf(...) so funktioniert??
Ich habe nicht behauptet, daß es so ginge.
Im Gegenteil, ich bin sicher daß es gar nicht geht ohne zumindest
einen benannten Parameter, weder so noch anders.
Wenn du Teile von mir zitierst, dann bitte nicht sinnentstellend.
Das war vielmehr die Frage an dich, wie du das lösen willst:
DerAlbi schrieb:> an die parameter kommt man ganz normal über die argumentliste...
DerAlbi schrieb:> Das ist unfug. Bevor schreiben, austesten:>>> void blah(...)> {>> }>>> blah(1, 4, "Hallo");> blah();>>> Wessen compiler meckert da?> Meiner nicht.
Aha.
Dann führ doch bitte mal die Internals von blah aus.
Ich hätte von dir gerne den Code in blah gesehen, so dass ich diese
Aufrufe machen kann
blah( "arg1" );
blah( 1 )
blah( 1, "arg1" );
blah( "arg1", "arg2" );
blah( 3.1415 );
blah( 3.1415f ); // der ist gemein. Vorsicht Falle
blah();
Für den Anfang genügt es vollkommen, wenn die Funktion die
Funktionsargumente einfach ausgibt. printf ist dafür fein.
Also: Wie sieht blah aus?
Nur weil ein bestimmter Compiler etwas nicht anmeckert, heisst das noch
lange nicht, das es richtig ist.
DerAlbi schrieb:> Ich finde den Parameter persönlich aber auch unnötig am anfang.> Eine VariableArgumentList basiert auf der Übergabe eines Pointers auf> eine Pointerliste und zusätzlich noch natürlich die Listengröße. Die> Typen in der Argumentliste sind nicht fest definiert. Auch nicht durch> den ersten parameter (man übergibt bei printf char* und hinten kommen> int, double und sonstiger unfug)
Du redest jetzt aber nicht von C, oder?
Vielleicht kannst du ja im C-Standard auch noch die Stelle benennen an
der von einer VariableArgumentList die Rede ist, die so realisiert sein
muss, wie du das beschreibst.
> Die> Typen in der Argumentliste sind nicht fest definiert.
Woher weiß dann die Funktion, welche Datentypen im Spiel sind?
DerAlbi schrieb:> Ordentlicher code muss einen> dummyparameter haben - verstanden
Ich glaub du misverstehst da etwas ganz gewaltig.
Es ist genau dieser, wie du es ausdrückst, Dummyparameter, der erst
variadische Funktionen möglich macht. Das was du als Dummyparameter
bezeichnest, ist der Schlüssel zu variadischen Funktionen. Und er ist
alles andere als einfach nur 'dummy'.
> Das ist unfug. Bevor schreiben, austesten:
Das kann ich zurückgeben. Hast du schon mal eine variadische Funktion
geschrieben? Wenn nein, dann empfehle ich dir mal eine zu
implementieren. Dann wird dir nämlich vieles klarer. Unter anderem zb
auch die automatischen Promotionregeln, die hier plötzlich zu greifen
anfangen.
Habt recht, bin dumm.
Hab schon Funktionen mit Varrgs geschrieben, hatte aber auch bisher
immer (zufällig) feste Parameter.
Dann hab ich das gelesen und ein kleines Testprogramm compilieren lassen
und gesehen dass mein compiler nicht meckert. Deswegen fehlschuss. Sry.
Auch wenns bei mir compiliert - was wohl die ausmahme ist - isses in der
Tat kompliziert dann auf die Args zuzugreifen.
Blöder Albi. :-)
Aber nu schlauer.