Pre-inkrement will nicht klappen

Ich habe eine (nicht dynamisch erzeugte) SyntaxBaumstruktur, die ich rekursiv abarbeiten möchte. Alle Baumknoten liegen hintereinander in einem Array, das Ganze sieht so aus:

struct Node
{
 unsigned short value;
 unsigned short (\*evalFunc)(struct Node\* n);
};

struct Node nodes[10];


unsigned short sub(struct Node\* n)
{
 //int result = 0;

 //result = (++n)-\>evalFunc(n);
 //result -= (++n)-\>evalFunc(n);

 return (++n)-\>evalFunc(n) - (++n)-\>evalFunc(n);
}

unsigned short getValue(struct Node\* n)
{
 return n-\>value;
}

void init()
{
 nodes[0].evalFunc = ⊂

 nodes[1].evalFunc = &getValue;
 nodes[1].value = 30;

 nodes[2].evalFunc = &getValue;
 nodes[2].value = 20;
}


void main()
{
 init();
 printf("%i\n", nodes[0].evalFunc(&nodes[0]));
}

Der Fehler steckt in einer Zeile der Funktion Sub:

return (++n)->evalFunc(n) - (++n)->evalFunc(n);

Hier soll *erst* der nächste Knoten ausgewählt werden und *dann* die evalFunc-Funktion von diesem ausgeführt werden, so dass folgender Ablauf ist:

Erster Knoten: SUB

  1. Nachfolgender Knoten: evaluiert 30
  2. Nachfolgender Knoten: evaluiert 20

=> 30 - 20

Leider werden die Knoten-Adressen nicht zuerst erhöht. Der auskommentierte Code zeigt zwar, wie ich das Problem lösen kann, aber zum einen möchte ich den Fehler begreifen, zum anderen muß ich einen Weg finden, wie ich lokale Variablen (in dem Fall: result) wg. der Rekursion vermeide (läuft auf Microcontroller)

Hallo

return (++n)->evalFunc(n) - (++n)->evalFunc(n);

Leider werden die Knoten-Adressen nicht zuerst erhöht. Der
auskommentierte Code zeigt zwar, wie ich das Problem lösen
kann, aber zum einen möchte ich den Fehler begreifen,

Die Auswertungsreihenfolge aller ‚n‘ ist
hier nicht definiert. Definiert ist ‚n‘
erst nach dem Sequenzpunkt „;“, nämlich
als n = n + 2. An allen Stellen innerhalb
des Ausdrucks kann ‚n‘ 0,1, oder 2 sein,
je nach Wetter.

zum anderen muß ich einen Weg finden, wie ich lokale
Variablen (in dem Fall: result) wg. der Rekursion
vermeide (läuft auf Microcontroller)

 unsigned short sub(struct Node\* n)
{
 return (
 n += 2, 
 (n-1)-\>evalFunc(n-1) - n-\>evalFunc(n)
 );
}

Trotzdem sieht Deine Sache ziemlich
kompliziert aus. Was hast Du denn vor?

Grüße

CMБ

Danke für die Antwort. Es geht um Genetische Programmierung. Die Programme werden als Syntaxbaum dargestellt und abgearbeitet, das alles geschieht auf einem Microcontrollerboard, welches einen Stack von 256bytes zur Verfügung stellt. Da ich
erst noch testen muß, ob eine ausreichende Tiefe mit dem begrenzten Stack rekursiv erreichen kann. Dafür muß halt gespart werden …

Hallo serethos,

Danke für die Antwort. Es geht um Genetische Programmierung.
Die Programme werden als Syntaxbaum dargestellt und
abgearbeitet, das alles geschieht auf einem
Microcontrollerboard, welches einen Stack von 256bytes zur
Verfügung stellt. Da ich erst noch testen muß, ob eine
ausreichende Tiefe mit dem begrenzten Stack rekursiv
erreichen kann. Dafür muß halt gespart werden

Dann würd’ ich das gar nicht rekursiv machen.
(würde wahrscheinlich auch einfacher und performanter)

Oder ist das die Vorgabe?

Grüße

CMБ

Ich habe auch als erstes versucht, die Rekursion mit einem eigenen Stack, der auf dem heap sitzt, nachzubilden. Da haben sich allerdings ein paar Probleme aufgetan und nun möchte ich ersteinmal einen plastischen Eindruck haben, wie groß die Bäume sein können, die ich rekursiv abarbeiten kann.

Hallo serethos,

Ich habe auch als erstes versucht, die Rekursion mit einem
eigenen Stack, der auf dem heap sitzt, nachzubilden. Da haben
sich allerdings ein paar Probleme aufgetan und nun möchte ich
ersteinmal einen plastischen Eindruck haben, wie groß die
Bäume sein können, die ich rekursiv abarbeiten kann.

OK

Laut Deinem Quelltext ist aber jeder Node immer
nur linear verlinkt. In diesem Falle brauchst Du
definitiv keine Rekursion, das Ganze lässt sich
(imho prinzipiell) einfacher auf einem simplen
linearen Vektor abbilden.

Oder werden die Nodes komplizierter ?

Gib doch mal ein konkretes Beispiel
vor, vielleicht fällt einem dann was ein :wink:

Grüße

CMБ

Es soll ungefähr so ablaufen. Stell Dir einfach einen Syntaxbaum in präfix- Schreibweise vor, z.B.:

(+ (- 10 20) (ifgt 10 20 50 60))

ifgt ist hier ein „Fall größer dann“ verglich zwischen Parameter1 und P2, der bei Erfolg P3 ansonsten P4 zurückgibt. Da diese Terme beliebig ineinander verschachtelt sein können (insbesondere die if-Ausdrücke!) muß ich sehr genau den Funktionszeiger über diesen Syntaxbaum im Auge behalten.

Hallo Fragewurm,

Du solltest einmal nachschauen, wie der Compiler mit lokalen Variablen umgeht und was wie wann auf den Stack geschmissen wird.
Möglicherweise bewirkt bei deinem Compiler das Schlüsselwort „register“ etwas. Hinzu kommt noch was der Compiler je nach Optimierungsstufe für Code generiert.
Dazu musst du aber den Assembler-Code anschauen, welcher dein Compiler erzeugt.

Oft ist es so, dass der Compiler, je nach Codekonstruct unterschiedlich optimalen Code erzeugt.
Grundsätzlich ist es unschön und potenziell gefährlich den Code an den Compiler anzupassen, aber wenn jedes Byte zählt, manchmal unumgänglich.
Allerdings sollte soetwas entsprechend dokumentiert werden, denn mit der nächsten Compiler-Version kann alles anders werden.
Zudem ist der Code für Micro-Controller meistens sowieso nicht einfach portierbar, da dies meist schon an einer anderen Portbelegung scheitert. Grundsätzlich sollte man zwar den Code schon so schreiben, dass er portierbar ist, was aber meist etwas mehr Code erzeugt und bei wenig RAM und ROM nicht immer sinnvoll ist.

Das ist so einer der Tricks, wieso Benchmarks des Herstellers A bessere Resultat auf der eigenen CPU ergeben als auf der CPU von Hersteller B. Lustigerweise ergeben aber die Benchmarks von Hersteller B auf seiner CPU wiederum bessere Ergebnise als auf der CPU des Herstllers A :wink:)

MfG Peter(TOO)

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo

Es soll ungefähr so ablaufen. Stell Dir einfach einen
Syntaxbaum in präfix- Schreibweise vor, z.B.:

(+ (- 10 20) (ifgt 10 20 50 60))

ifgt ist hier ein „Fall größer dann“ verglich zwischen
Parameter1 und P2, der bei Erfolg P3 ansonsten P4 zurückgibt.

OK, aber dann hast Du ja sowas:

( + 
 ( - 
 10 20
 ) 
 ( ifgt 
 10 20 ==\> 50 60
 )
)

was aber nicht mit Deiner „struct Node { … }“
übereinstimmt, da Du für „ifgt“ 4 Parameter hast.
Wie willst Du denn das unterbringen?

Grüße

CMБ

Recht hast Du. Der ursprünliche Quellcode ist veraltet, es müssten in Wirklichkeit einige Informationen mehr rein. Unter anderem auch ein Array von Node-Pointern, momentan fix auf fünf Stück definiert.

Hallo

es müssten in Wirklichkeit einige Informationen mehr rein.
Unter anderem auch ein Array von Node-Pointern, momentan
fix auf fünf Stück definiert.

Wie wird denn der Instruktionsbaum eingegeben
bzw. eingelesen bzw. vorgegeben?

Grüße

CMБ