Forum: PC-Programmierung Funktion über String aufrufen


von Mike (Gast)


Lesenswert?

Guten Morgen,

folgendes Problem: Ich habe eine Textdatei, in der u.a. ein 
Funktionsname steht. Die Datei wird geparst und dann soll die Funktion 
aufgerufen werden. Programmiert wird in C++.
1
// prototyp
2
int addiere( int a, int b );
3
4
.
5
.
6
.
7
8
int main()
9
{
10
   char Funktionsname[ 20 ];
11
12
   ParseTextDatei( &Funktionsname );
13
  
14
   // in der Textdatei steht jetzt die Funktion addiere, die aufgerufen werden soll
15
16
   return 0;
17
}
18
19
20
21
22
// implementierung
23
int addiere( int a, int b )
24
{
25
   return ( a + b );
26
}


Meine Idee ist, ein Array von Funktionspointern anzulegen, da das aber 
später über 400 Funktionen werden können ist das doch sehr umfangreich. 
Gibt da etwas besseres?

Danke für Hinweise.

Gruß Mike

von TestX (Gast)


Lesenswert?

Das klingt so als würdest du dir eine art scriptsprache bauen wollen.
Was du suchst nennt sich eval() ist aber aus guten Gründen nicht so 
einfach in C++ möglich.
 Der richtige Weg wäre es einen richtigen Tokenizer zu implementieren. 
Und ja wenn man das noch nie gemacht hat muss man hierzu einiges lesen 
etc. Für nen schnellschuß ist daher die variante einer hashmap string=> 
funktion das einfachste...besonderst wenn du es nur einmalig machst

von Mike (Gast)


Lesenswert?

TestX schrieb:
> Und ja wenn man das noch nie gemacht hat muss man hierzu einiges lesen

Daran soll es nicht scheitern und mir geht es auch nicht darum, dass ihr 
mir den fertigen Code hier reinschreibt. Ich suche einfach eine Methode 
um mein Problem zu lösen und mit meinen bisherigen Erfahrungen kam ich 
nur auf die Idee mit der Tabelle, wobei ich das auch noch nicht 
umgesetzt habe.

von Walter T. (nicolas)


Lesenswert?

Du willst also einen Interpreter bauen? Dann schau Dir existierende 
Interpreter an, z.B. LUA.

von Mike (Gast)


Lesenswert?

Walter T. schrieb:
> Du willst also einen Interpreter bauen?

Nicht wirklich. Wir haben eine GUI, die mit C++ programmiert wurde und 
diese soll nun erweitert werden. Diese Erweiterung soll, wie oben 
beschrieben, eine Funktion anhand eines Strings aufrufen.

Ich habe aber gerade gesehen, dass mit LUA, Python oder was auch immer 
in C++ einbinden kann. Ist das aber nicht viel mehr Aufwand als eine 
Tabelle anzulegen? Oder gibts hier rieseige Vorteile, die ich gerade 
noch nicht sehe?

von Robert L. (lrlr)


Lesenswert?


von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Mike schrieb:
> Ist das aber nicht viel mehr Aufwand als eine Tabelle anzulegen? Oder
> gibts hier rieseige Vorteile, die ich gerade noch nicht sehe?

Du hast bisher überhaupt noch nichts über den Anwendungszweck und 
weitere Inhalte dieser Beschreibungsdatei erwähnt. Ich vermute, dass in 
der Datei auch noch Aufrufparameter der betreffenden Funktion stehen 
sollen. Wie sieht es mit der Auswertung oder Darstellung der 
Rückgabewerte aus? Dann benötigt Ihr vermutlich eine Art 
Variablenkonzept. Und was ist mit den Typen der Parameter? Und 
Polymorphie?

Je nachdem, wie diese (und noch etliche andere Aspekte) berücksichtigt 
werden müssen, hat dies gewaltige Auswirkungen darauf, ob eine einfache 
Tabelle ausreicht, ein eigener Parser sinnvoll wäre oder doch eher auf 
eine Skriptsprache (mit C++-Interface) vorzuziehen wäre. Außer für sehr 
triviale Dinge würde ich heutzutage nicht versuchen, das Rad neu zu 
erfinden, sondern auf bestehenden Lösungen (Skriptsprache) 
zurückgreifen, auch wenn sie manchmal eher aufgebläht erscheinen.

von Mike (Gast)


Lesenswert?

Es sind alles void Funktionen und es werden nur diverse Dinger 
angetriggert. Es werden auch keine Parameter übergeben, von daher sollte 
in einem ersten Ansatz die Tabelle reichen. Aber wie das so ist, werden 
in der Zukunft sehr wahrscheinlich noch weitere Anforderungen kommen.

Ich gebe mich nun mal an den Ansatz mit der Tabelle und werde mal 5 
Funktionen speichern. Danach versuche ich mal den Ansatz über die 
Scriptsptrache. So habei ich beides mal gemacht.

von Georg (Gast)


Lesenswert?

Mike schrieb:
> Danach versuche ich mal den Ansatz über die
> Scriptsptrache

Überlege mal, was du da ins Script reinschreiben willst: eine 
case-Anweisung mit 400 Funktionsnamen und den dazugehörigen 
Funktionsaufrufen. Gewonnen gegenüber der Tabelle ist damit garnichts, 
es ist nur unnötig verkompliziert.

Was anderes ist es, die Script-Interpreter-Source als Vorlage zu 
benutzen, aber das ist auch Overkill für so eine einfache Zuordnung.

Georg

von Karl H. (kbuchegg)


Lesenswert?

Mike schrieb:

> Meine Idee ist, ein Array von Funktionspointern anzulegen, da das aber
> später über 400 Funktionen werden können

400 Schlüsselwörter?

Da würde ich mir ganz schwer eine Systematik und eine kleine Syntax 
überlegen, wie ich diese Anzahl runterbringen kann. Das its zwar 
momentan dann für dich mehr Aufwand aber deine Benutzer werden es dir 
auf lange Sicht danken.

Oh, und rangehen würde ich dann mit Compiler-Bau Tools.
Denn der Appetit wächst mit dem Essen. Irgendwann soll in deiner 'Script 
Sprache' dann  nämlich auch gerechnet werden können, Variablen werden 
gewünscht, Zugriff auf Werte des zu steuernden Systems die in Ausdrücken 
benutzt werden können, etc. etc. Und dann siehst du mit deiner 
Funktionstabelle (die funktionieren wird und die momentan sicherlich das 
einfachste ist) dann ziemlich alt aus.

: Bearbeitet durch User
von Mikro 7. (mikro77)


Lesenswert?

Mike schrieb:
> folgendes Problem: Ich habe eine Textdatei, in der u.a. ein
> Funktionsname steht. Die Datei wird geparst und dann soll die Funktion
> aufgerufen werden. Programmiert wird in C++.

Es gibt einen Zuordnung von Funktionsname (Zeichenkette) auf 
Funktionspointer. Es gibt eine Liste solcher Zuordnungen.

Die Aufgabe ist es, für einen gegebenen Funktionsnamen (Zeichenkette) 
den zugehörigen Funktionspointer zurückzuliefern.

Das ist das Problem? Ist das Parsen das Problem?

> Meine Idee ist, ein Array von Funktionspointern anzulegen, da das aber
> später über 400 Funktionen werden können ist das doch sehr umfangreich.

Wenn es 400 unterschiedliche Funktionen gibt, wirst du da kaum drum 
herum kommen, oder gibt es eine Herleitung für die 400 Funktionen, die 
die Menge reduziert?

> Gibt da etwas besseres?

Kommt drauf an. Ich habe die Problematik wohl nicht wirklich verstanden. 
;-)

von Mike (Gast)


Lesenswert?

S. J. schrieb:
> Wenn es 400 unterschiedliche Funktionen gibt, wirst du da kaum drum
> herum kommen, oder gibt es eine Herleitung für die 400 Funktionen, die
> die Menge reduziert?

Die Anzahl kann ich nicht reduzieren, da diese Funktionen bereits 
vorgegeben sind.



S. J. schrieb:
> Die Aufgabe ist es, für einen gegebenen Funktionsnamen (Zeichenkette)
> den zugehörigen Funktionspointer zurückzuliefern.

Genau, "mehr" nicht.

von Robert L. (lrlr)


Lesenswert?

400 ist doch "Peanuts" (ich sehe hier das Problem nicht???)

wenns schnell gehen soll, würde ich a HashTable machen, oder sowas..

(oder einfach meine vorschlag NICHT ignorieren 
Beitrag "Re: Funktion über String aufrufen" dort kann man wohl 
auch benutzerdefinierte funktionen hinzufügen..)

von Klaus W. (mfgkw)


Lesenswert?

Gibt es in der STL fertig als std::map.

Daraus macht man sich eine Zuordnung von String auf die Funktion bzw. 
einen Zeiger darauf.

Man kann sich aber auch eine eigene Klasse definieren, die jeweils eine 
Methode enthält (deine auszuführende Funktion) und selbst weiß, wie sie 
heißt.
Davon schmeisst man meinetwegen 400 in ein std::set und kann sie darin 
anhand des Namens finden.
Das ist etwas mehr in Richtung OOP als die schnöde Map mit 
Funktionszeigern.

von Mike (Gast)


Lesenswert?

Robert L. schrieb:
> oder einfach meine vorschlag NICHT ignorieren

keine Sorge, habe ich schon zur Kenntnis genommen. Danke.

Klaus W. schrieb:
> Gibt es in der STL fertig als std::map.

Ok, schaue ich mir auch mal an

von Mikro 7. (mikro77)


Lesenswert?

Mike schrieb:
>> Die Aufgabe ist es, für einen gegebenen Funktionsnamen (Zeichenkette)
>> den zugehörigen Funktionspointer zurückzuliefern.
>
> Genau, "mehr" nicht.

Dann (1) iterierst du über deine Liste/Vector/Array mit der Input 
Zeichenkette solange, bist du die passende Zuordnung gefunden hast.

Wenn es schneller gehen soll nimmst du (2) eine std::map. Bessere 
Performance bietet (3) std::unordered_map (C++11) oder das Boost 
Equivalent. Wenn es Super-Speed-schnell gehen soll, baust du dir eine 
(4) State Machine (Overkill!)

Ich würde (1) nehmen (kann man später optimieren) und erstmal gucken was 
denn ansonsten für Probleme auf dich zukommen. ;-)

von Walter T. (nicolas)


Lesenswert?

Mike schrieb:
> Diese Erweiterung soll, wie oben
> beschrieben, eine Funktion anhand eines Strings aufrufen.

Dann bleibt natürlich die Frage: Wie oft? Und wie oft ändert das sich?

von Mike (Gast)


Lesenswert?

Walter T. schrieb:
> Dann bleibt natürlich die Frage: Wie oft? Und wie oft ändert das sich?

Sehr sehr langsam. Der User kann sich Seiten generieren und nur, wenn er 
sich die Seite umgestaltet werden andere oder neue Funktionen 
aufgerufen.

von Walter T. (nicolas)


Lesenswert?

Mike schrieb:
> Sehr sehr langsam

Dann spricht ja nichts gegen eine einfache Tabelle mit Funktionspointer 
und -Namensstring, wenn diese nur selten durchsucht werden muß. Das 
Ergebnis kann ja beliebig zwischengespeichert werden.

von Andreas M. (amesser)


Lesenswert?

Warum nicht einfach einen lua Interpreter in das Programm einbetten. 
Jede Nutzer-Funktion die es gibt dann einfach beim lua registrieren. 
Dann kann quasi beliebiger Lua code ausgeführt werden, der Anwender ist 
also später nicht auf den reinen Funktionsaufruf beschränkt. (Die 
Anforderung kommt früher oder später sowieso)
Wir machen das bei unseren Gateways auch so.

von Pumuckl (Gast)


Lesenswert?

Andreas M. schrieb:
> Warum nicht

KISS. Er sollte das Ganze kapseln (register, call, ...) und fertig. 
Details eventuell irgendwann notwendiger Erweiterungen sind zum 
jetzigen Zeitpunkt sowieso unbekannt.

von Klaus W. (mfgkw)


Angehängte Dateien:

Lesenswert?

Mike schrieb:
> Klaus W. schrieb:
>> Gibt es in der STL fertig als std::map.
>
> Ok, schaue ich mir auch mal an

Das sieht lauffähig etwa aus wie in t.cpp.

Weil es etwas langweilig ist, kann man ab C++11 das auch mit 
Lamdafunktionen machen, dann braucht man nicht die Funktionen explizit 
hinschreiben und ihre Adresse übergeben, sondern definiert sie nebenbei 
beim Einfügen in die std::map<>.

von Klaus W. (mfgkw)


Lesenswert?

Klaus W. schrieb:
> Lamdafunktionen

sorry, die heißen Lambdafunktionen.

von c-hater (Gast)


Lesenswert?

Mike schrieb:

> folgendes Problem: Ich habe eine Textdatei, in der u.a. ein
> Funktionsname steht. Die Datei wird geparst und dann soll die Funktion
> aufgerufen werden. Programmiert wird in C++.

Falsche Wahl. Wenn man die Eigenschaften eine Interpretersprache haben 
wil, dann benutzt man einfach eine Interpreterprache. Capisce?

Wenn der Kulturschock nicht gar so groß sein soll, würde sich vielleicht 
C# anbieten. Denn C# kann notfalls sogar wirklich "interpretieren". 
Tatsächlich allerdings kann es was noch wesentlich besseres: 
JIT-kompilieren.

D.h.: Der Perfomance-Nachteil gegenüber C++ ist zwar vorhanden, teils 
sogar sehr störend ausgeprägt, aber zumindest der kompilierte 
"Scriptcode" wird wesentlich effizienter laufen als alle anderen 
Konstrukte, die mit C++ machbar wären. Allein deshalb, weil der 
"Scriptcode" im vollen Umfang von allen Optimierungen profitieren kann, 
denen C# und .net teilhaftig wurde...

von Sheeva P. (sheevaplug)


Lesenswert?

Klaus W. schrieb:
> Weil es etwas langweilig ist, kann man ab C++11 das auch mit
> Lamdafunktionen machen, dann braucht man nicht die Funktionen explizit
> hinschreiben und ihre Adresse übergeben, sondern definiert sie nebenbei
> beim Einfügen in die std::map<>.

Verzeih' bitte, aber Dein Beispiel "t_lambda.cpp" ist immer noch mit 
Funktionszeigern (meineFunktion_t) unterwegs...
1
#include <iostream>
2
#include <map>
3
#include <string>
4
#include <functional>
5
6
int main(void) {
7
    std::map< std::string, std::function<void(void)> > funcmap = {
8
        {"a", [](void) -> void { std::cout << "func a" << std::endl; }},
9
        {"b", [](void) -> void { std::cout << "func b" << std::endl; }},
10
        {"c", [](void) -> void { std::cout << "func c" << std::endl; }},
11
        {"q", [](void) -> void { exit(EXIT_SUCCESS); }}
12
    };
13
14
    std::string line;
15
    while(true) {
16
        std::cout << "which function do you want to call? -> ";
17
        std::cin >> line;
18
        // @todo check if $line is in %funcmap
19
        funcmap[line]();
20
    }
21
22
    return 0;
23
}

PS: Ich finde auch nicht, daß ein Programm seinen Benutzer auf bairisch 
(fränkisch?) beschimpfen sollte. Usability-Untersuchungen haben gezeigt, 
daß höfliche Programme vom Benutzer besser angenommen werden. ;-)

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

Klaus W. schrieb:
> Das sieht lauffähig etwa aus wie in t.cpp.

Man koennte das noch mit etwas Codegenerierung kombinieren, so dass man 
die Funktionen nicht selbst in die Tabelle eintragen muss.

Sobald es nennenswert komplizierter wird als in diesem Beispiel, kann 
man sich damit aber eine unwartbare Katastrophe frickeln und sollte auf 
etwas anderes umsteigen.

Grobe Skizze der Idee im Anhang.

von Klaus W. (mfgkw)


Lesenswert?

Sheeva P. schrieb:
> Verzeih' bitte, aber Dein Beispiel "t_lambda.cpp" ist immer noch mit
> Funktionszeigern (meineFunktion_t) unterwegs...

Das kann man natürlich noch tausendfach variieren, meinetwegen auch 
gerne mit std::function (dahinter vergirgt sich dann jeweils eine 
generierte Klasse mit einer Methode, die - eine Adresse hat und darüber 
aufgerufen wird).

Sheeva P. schrieb:
> PS: Ich finde auch nicht, daß ein Programm seinen Benutzer auf bairisch
> (fränkisch?) beschimpfen sollte. Usability-Untersuchungen haben gezeigt,
> daß höfliche Programme vom Benutzer besser angenommen werden. ;-)

Daß mit bairisch finde ich jetzt beleidigend; mit fränkisch hast du 
gerade noch die Kurve gekriegt.
Inwieweit solche Ausgaben wirklich beleidigend sind, liegt im Auge des 
Angesprochenen. Bei Franken ist so etwas nicht unbedingt böse gemeint.
Du darfst es gerne durch irgendwelche Kuschelsprüche ersetzen, dem 
Compiler wird es egal sein.

von Walter T. (nicolas)


Lesenswert?

Sheeva P. schrieb:
> Ich finde auch nicht, daß ein Programm seinen Benutzer auf bairisch
> (fränkisch?) beschimpfen sollte.

Aber wenn das doch so im Lastenheft steht?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Klaus W. schrieb:
> Das kann man natürlich noch tausendfach variieren, meinetwegen auch
> gerne mit std::function (dahinter vergirgt sich dann jeweils eine
> generierte Klasse mit einer Methode, die - eine Adresse hat und darüber
> aufgerufen wird).

Die function-Objekte sind schon sehr praktisch und haben seit ihrer
Einführung in C++11 bei mir die Funktionszeiger praktisch vollständig
verdrängt.

Ihr Vorteil liegt eben darin, dass sie im Gegensatz zu Funktionszeigern
nicht nur freie Funktionen und Klassenmethoden, sondern auch Closures,
Funktionen mit vorbelegten Argumenten, Instanzmethoden (zusammen mit
einer Objektreferenz) u.v.m. darstellen können. Gerade letztere sind in
der objektorientierten Programmierung ziemlich wichtig.

von Klaus W. (mfgkw)


Lesenswert?

Vollkommen richtig.

von Planlos (Gast)


Lesenswert?

Sheeva P. schrieb:
> std::map< std::string, std::function<void(void)> > funcmap

Sooo... da muss jetzt nur noch eine Parameter-Übergabe mit rein:

Mike schrieb:
> int addiere( int a, int b )
> {
>    return ( a + b );
> }

Und dann, nächste Woche, wenn die nächste Übungsaufgabe ansteht, müssen 
Funktionsaufrufe noch geschachtelt werden können:
> print(addiere(2,2))

Übernächste Woche soll dann die "addiere"-funktion durch einen 
infix-Operator '+' ersetzt werden.

Danach Punkt-vor-Strich, Klammerung, Variablen, ....

von beric (Gast)


Lesenswert?

Walter T. schrieb:
> Sheeva P. schrieb:
>> Ich finde auch nicht, daß ein Programm seinen Benutzer auf bairisch
>> (fränkisch?) beschimpfen sollte.
>
> Aber wenn das doch so im Lastenheft steht?

Dann kann man das immer noch im Pflichtenheft umschreiben ;-)

von Sebastian V. (sebi_s)


Lesenswert?

Yalu X. schrieb:
> Die function-Objekte sind schon sehr praktisch und haben seit ihrer
> Einführung in C++11 bei mir die Funktionszeiger praktisch vollständig
> verdrängt.

Man sollte noch erwähnen, dass es auch einige (kleine) Nachteile gibt. 
Die std::function Objekte sind recht groß und reservieren meistens 
dynamisch Speicher. Außerdem sind die Aufrufe der gespeicherten 
Funktionen etwas teurer weil ein virtual function call benötigt wird. 
Auf dem PC ist das wenig relevant, auf eine µc wäre man mit normalen 
function pointers vielleicht besser beraten.

von Mark B. (markbrandis)


Lesenswert?

Yalu X. schrieb:
> Die function-Objekte sind schon sehr praktisch und haben seit ihrer
> Einführung in C++11 bei mir die Funktionszeiger praktisch vollständig
> verdrängt.

Die gibt es doch aber nicht erst seit C++11, oder? Den 
Funktionsaufruf-Operator () kann man schon ziemlich lange überladen.

: Bearbeitet durch User
von Sheeva P. (sheevaplug)


Lesenswert?

Klaus W. schrieb:
> Sheeva P. schrieb:
>> Verzeih' bitte, aber Dein Beispiel "t_lambda.cpp" ist immer noch mit
>> Funktionszeigern (meineFunktion_t) unterwegs...
>
> Das kann man natürlich noch tausendfach variieren, meinetwegen auch
> gerne mit std::function (dahinter vergirgt sich dann jeweils eine
> generierte Klasse mit einer Methode, die - eine Adresse hat und darüber
> aufgerufen wird).

std::function ist hier nur der Typ der Funktion für das Map-Template; 
der eigentliche Lambda-Ausdruck ist jener Teil: "[...](...)->...{...}". 
Dabei handelt es sich um anonyme, also unbenannte Funktionen, welche 
zwar recht ähnlich wie ein Funktionszeiger arbeiten, aber eine bessere 
Typsicherheit bieten und den Kontext (im "[...]"-Teil) mitnehmen können. 
Guckstu: [1,2]

> Sheeva P. schrieb:
>> PS: Ich finde auch nicht, daß ein Programm seinen Benutzer auf bairisch
>> (fränkisch?) beschimpfen sollte. Usability-Untersuchungen haben gezeigt,
>> daß höfliche Programme vom Benutzer besser angenommen werden. ;-)
>
> Daß mit bairisch finde ich jetzt beleidigend; mit fränkisch hast du
> gerade noch die Kurve gekriegt.
> Inwieweit solche Ausgaben wirklich beleidigend sind, liegt im Auge des
> Angesprochenen. Bei Franken ist so etwas nicht unbedingt böse gemeint.
> Du darfst es gerne durch irgendwelche Kuschelsprüche ersetzen, dem
> Compiler wird es egal sein.

Entschuldige, ich wollte Dich nicht beleidigen und kenne mich mit dem 
kulturellen Kontext fränkischer Umgangsformen auch nicht so gut aus.


[1] http://de.cppreference.com/w/cpp/language/lambda
[2] http://www.drdobbs.com/cpp/lambdas-in-c11/240168241

von Klaus W. (mfgkw)


Lesenswert?

Mark B. schrieb:
> Die gibt es doch aber nicht erst seit C++11, oder?

ja, aber 2011 ist schon rum - jetzt darf man das nehmen :-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mark B. schrieb:
> Yalu X. schrieb:
>> Die function-Objekte sind schon sehr praktisch und haben seit ihrer
>> Einführung in C++11 bei mir die Funktionszeiger praktisch vollständig
>> verdrängt.
>
> Die gibt es doch aber nicht erst seit C++11, oder? Den
> Funktionsaufruf-Operator () kann man schon ziemlich lange überladen.

Das schon, aber die Klasse function und das zugehörige Header-File
functional wurden erst in C++11, zusammen mit der Lambda-Syntax
eingeführt. Vorher hat man sich etwas Entsprechendes entweder selber
zusammengestrickt, oder man hat die Boost-Bibliotheken Function,
Bind und Lambda benutzt, aber beides natürlich ohne die neue Syntax.

von Sheeva P. (sheevaplug)


Angehängte Dateien:

Lesenswert?

Sebastian V. schrieb:
> Die std::function Objekte sind recht groß und reservieren meistens
> dynamisch Speicher. Außerdem sind die Aufrufe der gespeicherten
> Funktionen etwas teurer weil ein virtual function call benötigt wird.
> Auf dem PC ist das wenig relevant, auf eine µc wäre man mit normalen
> function pointers vielleicht besser beraten.

Das hat mich dann doch interessiert, und ich bin zu folgenden 
Ergebnissen gekommen (Dateien im Anhang):
1
g++ -std=c++11 -O0    point.cpp   -o point
2
g++ -std=c++11 -O0    main.cpp   -o main
3
63336   main
4
46312   point
5
31152   main
6
22952   point
7
8
g++ -std=c++11 -O1    point.cpp   -o point
9
g++ -std=c++11 -O1    main.cpp   -o main
10
21512   main
11
20208   point
12
14760   main
13
14752   point
14
15
g++ -std=c++11 -O2    point.cpp   -o point
16
g++ -std=c++11 -O2    main.cpp   -o main
17
21544   main
18
20248   point
19
14752   main
20
14744   point
21
22
g++ -std=c++11 -O3    point.cpp   -o point
23
g++ -std=c++11 -O3    main.cpp   -o main
24
25528   main
25
20128   point
26
18848   main
27
14744   point
28
29
g++ -std=c++11 -Os    point.cpp   -o point
30
g++ -std=c++11 -Os    main.cpp   -o main
31
21432   main
32
15768   point
33
14720   main
34
10616   point

Spannend, daß -O{1,2,s} bei der main.cpp beinahe gleichauf liegen und 
-O3 sogar ein deutlich größeres Kompilat erzeugt, während bei der 
Version mit Funktionszeigern nur -Os so richtig was nutzt (g++ Ubuntu 
4.9.1-16ubuntu6).

Mit Link Time Optimization liegen die beiden Varianten dann allerdings 
wieder deutlich näher beieinander:
1
g++ -std=c++11 -O0 -flto    point.cpp   -o point
2
g++ -std=c++11 -O0 -flto    main.cpp   -o main
3
56176   main
4
39840   point
5
31152   main
6
22952   point
7
8
g++ -std=c++11 -O1 -flto    point.cpp   -o point
9
g++ -std=c++11 -O1 -flto    main.cpp   -o main
10
20720   main
11
19456   point
12
14752   main
13
14744   point
14
15
g++ -std=c++11 -O2 -flto    point.cpp   -o point
16
g++ -std=c++11 -O2 -flto    main.cpp   -o main
17
20704   main
18
19440   point
19
14744   main
20
14736   point
21
22
g++ -std=c++11 -O3 -flto    point.cpp   -o point
23
g++ -std=c++11 -O3 -flto    main.cpp   -o main
24
20704   main
25
19440   point
26
14744   main
27
14736   point
28
29
g++ -std=c++11 -Os -flto    point.cpp   -o point
30
g++ -std=c++11 -Os -flto    main.cpp   -o main
31
16496   main
32
15120   point
33
10624   main
34
10616   point

Nachtrag: könnte ein Moderator bitte die kleinere "compile.sh" löschen? 
Lieben Dank.

[Mod: Hab's gelöscht]

THX!

: Bearbeitet durch User
von sebastian (Gast)


Lesenswert?

Sheeva P. schrieb:
>> Die std::function Objekte sind recht groß und reservieren meistens
>> dynamisch Speicher. Außerdem sind die Aufrufe der gespeicherten
>> Funktionen etwas teurer weil ein virtual function call benötigt wird.
Hier geht es nicht um Code-Größe.

>
> Das hat mich dann doch interessiert, und ich bin zu folgenden
> Ergebnissen gekommen (Dateien im Anhang):
Du hast Code-Größe gemessen.

von Sebastian V. (sebi_s)


Lesenswert?

In der Codegröße scheint das tatsächlich kaum Unterschied zu machen. Im 
übrigen sind die Unterschiede zwischen deinen Beispielen größer als sie 
sein müssen. In der Variante mit Function Pointers kann man weiterhin 
Lambdas nutzen (sofern diese keine captures speichern). Der einzige 
Unterschied wäre also nur den Typ der Map von std::function<void(void)> 
auf void(*)(void) zu ändern.

von Sheeva P. (sheevaplug)


Lesenswert?

sebastian schrieb:
> Du hast Code-Größe gemessen.

Ja, für den Rest war ich zu faul, das ist für so kleine Schnipselchen 
aber meistens ein ganz guter Anhaltspunkt. Hier offenbar nicht; der 
Effekt bei der Optimierung ist zwar ähnlich, dafür hängt die 
Funktionszeigerversion die Lambdaversion viel deutlicher ab:
1
g++ -std=c++11 -O0 -flto    point.cpp   -o point
2
g++ -std=c++11 -O0 -flto    main.cpp   -o main
3
   text    data     bss     dec     hex filename
4
  25146     816     728   26690    6842 main
5
  17895     808     600   19303    4b67 point
6
7
g++ -std=c++11 -O1 -flto    point.cpp   -o point
8
g++ -std=c++11 -O1 -flto    main.cpp   -o main
9
   text    data     bss     dec     hex filename
10
   8787     800     776   10363    287b main
11
   7145     792     648    8585    2189 point
12
13
g++ -std=c++11 -O2 -flto    point.cpp   -o point
14
g++ -std=c++11 -O2 -flto    main.cpp   -o main
15
   text    data     bss     dec     hex filename
16
   9182     792     776   10750    29fe main
17
   7416     784     648    8848    2290 point
18
19
g++ -std=c++11 -O3 -flto    point.cpp   -o point
20
g++ -std=c++11 -O3 -flto    main.cpp   -o main
21
   text    data     bss     dec     hex filename
22
  10734     792     776   12302    300e main
23
   8812     784     648   10244    2804 point
24
25
g++ -std=c++11 -Os -flto    point.cpp   -o point
26
g++ -std=c++11 -Os -flto    main.cpp   -o main
27
   text    data     bss     dec     hex filename
28
   6910     768     776    8454    2106 main
29
   5485     760     648    6893    1aed point

: Bearbeitet durch User
von Sven B. (scummos)


Lesenswert?

Der moc in Qt macht sowas, falls du das benutzt.
http://doc.qt.io/qt-5/qmetaobject.html#invokeMethod

von Karl (Gast)


Lesenswert?

Georg schrieb:
> ine
> case-Anweisung mit 400 Funktionsnamen und den dazugehörigen
> Funktionsaufrufen.

Wenn man Python als Sprache verwendet braucht man keine case-Anweisung. 
Man kann dort einen String direkt mit dem Befehl exec ausführen.

von Klaus W. (mfgkw)


Lesenswert?

BTW es gibt auch noch eine ganz andere Variante:
Man könnte die aufzurufenden Funktionen in eine *.so (Windows: *.DLL) 
packen und zur Laufzeit vom Hauptprogramm nachladen mit 
dlopen()/dlclose() (Windows: LoadLibrary() o.s.ä.).
Dann kann man anhand des gewünschten Namens das zugehörige Symbol bauen 
(wahrscheinlich _ davor) und mit dlsym() (Windows: GetProcAddr() 
o.s.ä.).
Das liefert erinen Zeiger auf die Funktion, die man dann aufrufen kann.

Ist erstmal umständlicher, aber öffnet die Möglichkeit durch Austauch 
der .so andere Funktionen laden zu können, ohne das Hauptprogramm ändern 
zu müssen (z.B. für Anpassungen, die sich ein Kunde selbst bauen oder 
anderweitig beschaffen kann -> Plugin).

von Qt_Peter (Gast)


Lesenswert?

Mike schrieb:
> Wir haben eine GUI, die mit C++ programmiert wurde und
> diese soll nun erweitert werden.

Hallo,

ich gehe mal stark davon aus, dass du dann Qt nutzt?!?

Qt kann das nämlich mittels QMetaObject::invokeMethod. Einfach den 
Funktionsnamen als String übergeben und deine Funktion noch als Slot 
definieren und schon sollte das klappen. Funktioniert sogar mit 
Rückgabewerten deiner Funktion

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.