mikrocontroller.net

Forum: Compiler & IDEs [C] variable anzahl an Argumenten an einen Funktionspointer


Autor: Markus, der Kaffee-Säufer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Mark .. (mork)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meinst Du sowas wie bei printf? Dann such mal nach va_list und änliches. 
Beispiel weiter unten auf 
http://www.cplusplus.com/reference/clibrary/cstdar...

MfG Mark

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Markus, der Kaffee-Säufer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
  int printf( const char*, ... );
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.

Autor: DerAlbi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist unfug. Bevor schreiben, austesten:


void blah(...)
{

}


blah(1, 4, "Hallo");
blah();


Wessen compiler meckert da?
Meiner nicht.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und wie kommst du jetzt an die Parameter ran?

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat er bestimmt schon ausgetestet :-)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DerAlbi schrieb:
> Das ist unfug. Bevor schreiben, austesten:
>
>
> void blah(...)
> {
>
> }
>
>
> blah(1, 4, "Hallo");
> blah();
>
>
> Wessen compiler meckert da?
> Meiner nicht.

Meiner übrigens schon:
klaus@i4a:~ > cat t.c
void t(...)
{
}
klaus@i4a:~ > gcc -Wall t.c
t.c:1: error: ISO C requires a named argument before ‘...’

Vielleicht solltest du mal deinen K&R-Compiler updaten :-)

PS: Hattest du das eigentlich getestet?

Autor: DerAlbi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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. :-)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DerAlbi schrieb:
> an die parameter kommt man ganz normal über die argumentliste...

Reden wir beide von C?

Wie soll das gehen? Z.B. so:
void t(...)
{
  printf( ... ); // alles ausgeben
}
Man lernt ja nie aus ...

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DerAlbi schrieb:
> aber interessant das mache compiler wirklich meckern. Ist mir noch nicht
> passiert, sry.

JEDER ISO-C-Compiler muß das meckern.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DerAlbi schrieb:
> an die parameter kommt man ganz normal über die argumentliste...
für va_start braucht man aber den ersten parameter mit namen.

Autor: DerAlbi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: DerAlbi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.