Forum: PC-Programmierung C++ Code zur Laufzeit dynamisch zusammenstellen


von CPPDYN (Gast)


Lesenswert?

Hallo,

ich möchte ein C++ Programm versuchen zu schreiben wo Bedingungen aus 
verschiedenen vorgefertigten Modulen (Funktionen, Operatoren(> < && ||)) 
per Zufall zusammengestellt werden und dann ausgeführt werden.

Als grobes Beispiel es gibt 100 Funktionen mit Rückgabewerten (genannt 
FR) und es gibt Operatoren wie < > && || und es gibt weitere 100 
Funktionen mit bestimmten Aktionen (genannt FA). Nun soll random daraus 
eine Kombination erstellt werden können wie zB:

if(FR1() > FR2() && FR4 < FR8 && FR1 < FR9)
{
   FA3();
}

Meine Frage wäre wie würde man das grundsätzlich angehen von der 
Datenstruktur? In welcher Datenstruktur erzeugt man so eine 
Aneinanderreihung von Funktionen und Operatoren die miteinander zur 
Laufzeit dynamisch kombiniert ausgeführt werden sollen? Und wie setzt 
man das um damit auch das Programm performant bleibt?

Ein Ansatz wäre sicherlich auf Stringbasis die Code-Module nach 
funktionierenden Regeln zusammenstellen zu lassen und dann zur Laufzeit 
zu Libs zu kompilieren und einzubinden (zb dlopen()). Etwa wie in dieser 
Ansatz: 
https://stackoverflow.com/questions/11016078/is-it-possible-to-create-a-function-dynamically-during-runtime-in-c/11016382#11016382

Meine Frage wäre, geht so etwas auch ohne besondere Perfomance-Verluste 
direkt in C++ mit Hilfe irgendwelcher dynamisch erstellten 
Datenstrukturen welche dann den entsprechenden Codeablauf von Funktionen 
und Operatoren abgearbeiten können? Wo packe ich sozusagen die 
Kombination solcher Module rein was als Ganzes dann natürlich noch 
ausführbar sein soll?

Grüße

von Michael B. (laberkopp)


Lesenswert?

Du hast was prinzipielles bei compilieren vs. Laufzeit nicht verstanden.

CPPDYN schrieb:
> Meine Frage wäre wie würde man das grundsätzlich angehen

Man programmiert einen Interpreter.

von Vincent H. (vinci)


Lesenswert?

Was du suchst ist eine "embedded scripting language", sprich eine 
Skriptsprache die eingebunden und ausgeführt werden kann. Eine Liste 
solcher Sprachen gibt es etwa hier:

https://github.com/dbohdan/embedded-scripting-languages

Der prominenteste Vertreter ist wohl Lua, der vor allem in der 
Spieleindustrie sehr häufig zum Einsatz kommt. Zu Lua würde ich auch 
persönlich raten weil:
-) Der Core sehr klein ist. (~200kB)
-) Die Community groß und die Entwicklung im Gegensatz zu vielen anderen 
Vertretern auf der Liste aktiv ist.
-) Die C++ Bindings in Form von sol2 (https://github.com/ThePhD/sol2) so 
ziemlich das Beste sind was es gibt.

/edit
Deutsche Sprache...

: Bearbeitet durch User
von Dirk K. (merciless)


Lesenswert?

Kannst auch mal nach dem Command-Pattern
suchen, ein ähnliches Problem hab ich mal
damit gelöst.

merciless

von CPPDYN (Gast)


Lesenswert?

Klingt interessant allerdings hab ich quasi nur von C++ eine Ahnung. 
Wäre das was ich will nicht auch direkt in C++ möglich ohne auf eine 
andere Sprache zurückgreifen zu müssen?

Performancemäßig klingt das auch nicht gut: "Interpretierter Code ist in 
etwa fünf bis 20 Mal langsamer als kompilierter Code"
https://de.wikipedia.org/wiki/Interpreter#Eigenschaften

von zitter_ned_aso (Gast)


Lesenswert?

In einem Array aus Funktionszeigern alle 100 Funktionen ablegen und dann 
diese per Zufall aufrufen?

Natürlich müssen dann diese Funktionen die gleiche Signatur haben.

Beitrag #6330400 wurde von einem Moderator gelöscht.
von CPPDYN (Gast)


Lesenswert?

Dirk K. schrieb:
> Kannst auch mal nach dem Command-Pattern
> suchen, ein ähnliches Problem hab ich mal
> damit gelöst.
>
> merciless

Meinst du damit OOP also per virtuelle Funktionen etc etwas bauen?

von leo (Gast)


Lesenswert?

CPPDYN schrieb:
> if(FR1() > FR2() && FR4 < FR8 && FR1 < FR9)
> {
>    FA3();
> }

Bei dem Durcheiander voon Funktionsaufrufen und Variablen habe ich so 
meine Zweifel ...

> Meine Frage wäre wie würde man das grundsätzlich angehen von der
> Datenstruktur?

... aber schau dir mal
https://www.gnu.org/software/libmatheval/
an. Du baust einen String zusammen, der dann interpretiert wird.

leo

von CPPDYN (Gast)


Lesenswert?

zitter_ned_aso schrieb:
> In einem Array aus Funktionszeigern alle 100 Funktionen ablegen und dann
> diese per Zufall aufrufen?
>
> Natürlich müssen dann diese Funktionen die gleiche Signatur haben.

interessanter Ansatz das wäre sogar ein performant, aber wie würde man 
dann das mit den Verknüpfungen der Funktionen per Operatoren machen? 
Muss ich nochmal überlegen...

von zitter_ned_aso (Gast)


Lesenswert?

CPPDYN schrieb:
> dann das mit den Verknüpfungen der Funktionen per Operatoren machen?

Genauso mit Zeigern?

Erst mal Funktionen erzeugen:
1
                                                                        
2
bool foo_and(int (fp1)(void), int (fp2)(void)){                         
3
   return fp1() && fp2();                                               
4
}                                                                       
5
                                                                        
6
bool foo_or(int (fp1)(void), int (fp2)(void)){                          
7
   return fp1() || fp2();                                               
8
}
9
10
usw.
Und dann auch diese in einem Array von Funktionszeigern unterbringen.

Aber wie kann es
CPPDYN schrieb:
> und es gibt weitere 100
> Funktionen mit bestimmten Aktionen (genannt FA).

100 Funktionen geben? Da steht doch eine if-Anweisung. Und diese hat nur 
zwei Zustände (true/false). Wie können diese 100 Fuktionen auf zwei 
Zustände verteilt werden? Auch per Zufall?

von zitter_ned_aso (Gast)


Lesenswert?

zitter_ned_aso schrieb:
> bool foo_and(int (*fp1)(void), int (*fp2)(void)){

Funktionszeiger

von CPPDYN (Gast)


Lesenswert?

zitter_ned_aso schrieb:
> 100 Funktionen geben? Da steht doch eine if-Anweisung. Und diese hat nur
> zwei Zustände (true/false). Wie können diese 100 Fuktionen auf zwei
> Zustände verteilt werden? Auch per Zufall?

war natürlich erstmal nur ein Beispiel, aber ja im Grunde alles per 
Zufall, aus den 100 Funktionen mit Rückgabewert wird in Kombi mit 
zufälligen Operatoren eine Bedingung gemacht bei der auch wiederum 
zufällig sein kann wieviele Bedingungen aneinandergehängt werden (durch 
zB && ||). Wenn dann Bedingung erfüllt ist, dann soll eine der 
Aktionsfunktionen ausgeführt werden die auch wiederum zufällig gewählt 
ist...

Interessanter Ansatz mit den Funktionszeigern weil das auch schön 
low-level ist. Die Frage wäre auch ob man dann auch langfristig 
Verzweigungen (verschachtelte ifs... erzeugen könnte). Muss später mal 
ein paar Sachen testen... :-)

von Udo S. (urschmitt)


Lesenswert?

CPPDYN schrieb:
> aber ja im Grunde alles per
> Zufall, aus den 100 Funktionen mit Rückgabewert wird in Kombi mit
> zufälligen Operatoren eine Bedingung gemacht bei der auch wiederum
> zufällig sein kann wieviele Bedingungen aneinandergehängt werden (durch
> zB && ||). Wenn dann Bedingung erfüllt ist, dann soll eine der
> Aktionsfunktionen ausgeführt werden die auch wiederum zufällig gewählt
> ist...

Klingt nach Kunst.

von Dirk K. (merciless)


Lesenswert?

CPPDYN schrieb:
> Dirk K. schrieb:
>> Kannst auch mal nach dem Command-Pattern
>> suchen, ein ähnliches Problem hab ich mal
>> damit gelöst.
>>
>> merciless
>
> Meinst du damit OOP also per virtuelle Funktionen etc etwas bauen?
Hier ein Beispiel (ziemlich Pseudocode):
Ich habe damit komplexe mathematische Formeln
flexibel in einer DB abgelegt und zur Laufzeit
die Formel mit Hilfe von einzelnen Commands
zusammengestöpselt. Jede Formel lag als
Baumstruktur in einer Tabelle abgelegt.
So konnte man durch Änderungen in der DB
die Berechnungsvorschrift ändern, ohne neu
kompilieren zu müssen. Hochperformant ist
das natürlich nicht, aber sehr flexibel.
1
// Calculator-Interface
2
class ICalculator
3
{
4
public:
5
  double Calc();
6
}
7
8
// Addition
9
class Add : public ICalculator
10
{
11
private:
12
  ICalculator * left;
13
  ICalculator * right;
14
  
15
public:  
16
  Add(ICalculator * left, ICalculator * right)
17
  {
18
    this->left = left;
19
    this->right = right;
20
  }
21
22
  virtual double Calc()
23
  {
24
    return left->Calc() + right->Calc();
25
  }
26
}
27
28
// Multiplikation
29
class Sub : public ICalculator
30
{
31
private:
32
  ICalculator * left;
33
  ICalculator * right;
34
  
35
public:  
36
  Sub(ICalculator * left, ICalculator * right)
37
  {
38
    this->left = left;
39
    this->right = right;
40
  }
41
42
  virtual double Calc()
43
  {
44
    return left->Calc() - right->Calc();
45
  }
46
}
47
48
// const Value
49
class Const : public ICalculator
50
{
51
private:
52
  double value
53
  ICalculator * right;
54
  
55
public:  
56
  Const(double value)
57
  {
58
    this->value = value;
59
  }
60
61
  virtual double Calc()
62
  {
63
    return value;
64
  }
65
}
66
67
// Anwendung (die magic numbers stammten natürlich 
68
aus Variablen, die zur Laufzeit geändert wurden)
69
// result = (4711-27) + 42;
70
ICalculator * calc = new Add(new Sub(new Const(4711), new Const(27)), new Const(42));
71
double result = calc->Calc();

merciless

von Peter (Gast)


Lesenswert?

Wenn es dir ums lösen von mathematischen Ausdrücken geht, kannst du z.B. 
auch GNU Octave einbinden und das die Auswertung erledingen lassen. Oder 
Python. Bei beiden kannst du dir die Implementierung anschauen, wie man 
einen Interpreter schreibt.

von cppbert (Gast)


Lesenswert?

Es kommt sehr darauf an was du genau erreichen möchtest, einfache 
logische Operationen?, das komplette Typenspektrum von C++?, Funktionen 
mit n Parametern, Nur Ints oder auch Float, Strings? Was bedeutet für 
dich Performanz, genau so schnell wie kompiliert?

Wenn du dein Ziel so abstrakt laesst ist es schwierig dir konkrete Tips 
zu geben

Falls es nur einfache Operationen sind könntest du damit den Code 
dynamisch erzeugen, mit relativ gleicher Performanz
https://asmjit.com

von A. S. (Gast)


Lesenswert?

Das geht prinzipiell auch per Textfresser: 2 Coderümpfe erstellen, und 
den random-Code dazwischenschieben, compilieren, ausführen.

Aber ich fürchte, ich weiss nicht, wozu, also kann ich auch nicht ahnen, 
worauf es Dir ankommt.

von Racketeer (Gast)


Lesenswert?

@TO: Sieh Dir mal Racket an (oder andere interpretierte Sprachen, die 
erstklassige Funktionsobjekte unterstützen).

von Programmiersprachentheaterintendant (Gast)


Lesenswert?

Das haben einige sehr erfolgreich bereits umgesetzt, ist lange her.
Herausgekommen sind dabei so Sachen wie Python , Java , Perl , 
Lua ...

Nur zu: richtig gute C++ Programmierer welche das Rad nochmals erfinden 
sind immer gefragt!

von mh (Gast)


Lesenswert?

Programmiersprachentheaterintendant schrieb:
> Das haben einige sehr erfolgreich bereits umgesetzt, ist lange her.
> Herausgekommen sind dabei so Sachen wie [...] , Perl ,
> [...] ...

Ich habe es gewusst, Perl ist eine rein zufällige Kombination von 
Operatoren und Funktionen!

von Sven B. (scummos)


Lesenswert?

Nimm einen std::vector auf std::function<> und shuffle() den, dann 
schreib für die Operatoren irgendwas, was zwei Argumente nimmt und einen 
zufälligen Operator drauf anwendet. Wenn das was du beschreibst 
tatsächlich alles ist was du machen willst, gibt es wirklich einen 
Haufen einfache Lösungen für das Problem.

von Tom K. (ez81)


Angehängte Dateien:

Lesenswert?

Sven B. schrieb:
> Nimm einen std::vector auf std::function<>
Mit Lambdas kombiniert macht das richtig Spaß. Sowas ist natürlich 
unmöglich zu debuggen.

von Jemand (Gast)


Lesenswert?

LLVM unterstützt JIT-Kompilierung. Ist wahrscheinlich nur völliger 
Overkill.

von Programmiersprachentheaterintendant (Gast)


Lesenswert?

mh schrieb:
> Programmiersprachentheaterintendant schrieb:
>> Das haben einige sehr erfolgreich bereits umgesetzt, ist lange her.
>> Herausgekommen sind dabei so Sachen wie [...] , Perl ,
>> [...] ...
>
> Ich habe es gewusst, Perl ist eine rein zufällige Kombination von
> Operatoren und Funktionen!

Natürlich stimmt das so, auch wenn Du nur die Syntax meinst :-) (ich 
auch!)

Die Zufälligkeit ist aber auch ganz bestimmt der 
interessante/schwierige Teil an der Fragestellung des TOs...

von Marius W. (marwin)


Lesenswert?

CPPDYN schrieb:
> Klingt interessant allerdings hab ich quasi nur von C++ eine Ahnung.

Nein. Hast du nicht.

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.