gibt es ein tool o.ä. um folgendes zu erreichen: int main() { function1(); function2(); function1(); return(0); } void function1() { befehl11; befehl12; befehl13; } void function2() { befehl21; befehl22; befehl23; } || || Auflösen der || Funktionsaufrufe \/ int main() { befehl11; befehl12; befehl13; befehl21; befehl22; befehl23; befehl11; befehl12; befehl13; return(0); } ich will also in der main (oder wo auch immer) den jeweiligen funktionsaufruf durch den inhalt der entsprechenden funktion ersetzen. vielleicht kennt ja jemand ein tool welches sowas ermöglicht - ich möchte mir einfach nur die zeit sparen es selbst schreiben zu müssen, ich brauche das eigentlich nur zum schnellen debuggen und möchte die funktionen dazu aufgelöst haben. hintergrund ist (um den sinn vll etwas zu verdeutlichen) folgender: ich rufe zb die function1() mehrmals im programm auf, will zum debuggen dieser function dann einen "trigger" setzen. dieser würde ja aber immer aufgerufen werden, wenn ich die function1() rufe, deswegen will ich alle funktions-aufrufe aufgelöst haben, damit ich den trigger manuell an die richtige stelle setzen kann, und will nicht jedesmal mit copy'n'paste alles hin&her kopieren müssen. mfg
Je nach compiler kannst du unter "inline" oder "inlining" was finden. Dann das ganze durch den Präprozessor jagen, und du hast, was du willst.
...diese Antwort wird ihm sicher weiterhelfen Karl. Ich kenne mich in diesem Zusammenhang nicht sonderlich gut aus, aber sollte es nicht möglich sein ein make-file dementsprechend abzuändern, dass dieses die von Kola angesprochene Lösung bietet? Das wäre doch zumindest ein wenig mehr Bequemlichkeit, auch wenn es kein wirkliches "Tool" ist.
Theoretisch ist vieles möglich. In der Praxis kann man sich z.B. Probleme mit lokalen Variablen einhandeln. Noch schlimmer wird es, wenn z.B. rekursive Funktionen im Spiel sind. Im Einzelfall mag es möglich und vielleicht auch sinnvoll sein, Funktionen derart zu entrollen. Aber wie gesagt im Einzelfall bei genauer Analyse der Source und wenn man genau weiss wofür. Als sinnvollen Einzelfall zähle ich nicht "die Erleichterung beim Debuggen". Im Gegenteil - das Debuggen wird denke ich deutlich schwieriger. Mit den Funktionen kann man prima Breakpoints an den Funktionsanfang setzen und man debuggt dann genau eine Codestelle. woher man kommt, kann man prima mit dem Stackinspektor sehen. Und die lokalen Variablen und Funktionsargumente auch... Bei entrollten Funktioen muss man Breakpoints an alle (!) Codestellen setzen, wo die Funktion eingesetzt wurde (oder man debuggt sich mühsam sequentiell durchs Programm). Bei µC mit ggf. einer begrenzten Zahl von möglichen Breakpoints kann das schon das Killerargument sein.
Ach so - das mit dem Trigger kann man auch anders lösen. Im einfachen Fall z.B. so: Du kannst eine globale Variable debuglevel anlegen und dann zur Laufzeit mit dem Debugger ändern. Innerhalb der zu untersuchenden Funktion machst du eine Abfrage der Variable und setzt einen Breakpoint auf den Fall wo die Abfrage zutrifft. Moderne Debugger haben auch Möglichkeiten bedingte Breakpoints zu setzen. Z.B. der Breakpoint wird scharf, wenn die Stelle x-mal überlaufen wurde oder eine Variable einen betimmten Wert hat...
Oder man setzt den Breakpoint ganz einfach an die Stelle an der der interssierende Aufruf erfolgt. Debugger bleibt dort stehen, einmal ein Single Step in die Funktion hinein und man ist dort.
hallo, erstmal vielen dank für die antworten. das problem in meinem fall ist einfach, dass mir von vornherein kein "software"-debugger zur verfügung steht (also nichts mit single-step, register "mal eben nebenbei" auslesen etc pp), weil ich den code für den powerpc quasi nur im "text"-editor schreibe (ok, so schlimm ist es nicht, der editor hat schon syntax-highlighting etc), ich den code dann über eine putty-verbindung auf einer anderen maschine kompiliere und auf einer dritten für den mpc zur verfügung stelle. breakpoints zu implementieren habe ich schon versucht, aber das problem ist dann manchmal einfach folgendes: ich habe eine funktion die dafür verantwortlich ist, dass ein bestimmtes paket (konkret für USB) vorbereitet und gesendet wird...nun kann man sich leicht vorstellen, dass diese funktion hunderte male (teilweise durch schleifen etc) aufgerufen wird, bevor ich an die für mich interessante stelle komme.wann das sein wird, kann ich mir zwar vorher ausrechnen, aber es ist ja nie gesagt, dass zwischendurch nicht mal ein paket abgewiesen wird (durch das angeschlossene usb-device) und dieses erneut gesendet werden muss...und schon kommt die rechnung nicht mehr hin. vor die funktionsaufru (zb in der main) den breakpoint (in meinem fall eher ein triggersignal, weil ich das programm nat nicht anhalten kann) zu setzen macht off wegen der zeitlichen auflösung keinen sinn, weil selbst bei 2GS/s-oszis nichts mehr zu machen ist, wenn der trigger zu weit vom eigentlich zu untersuchenden ereignis in der untersuchten funktion ist. also vielleicht trägt das ein wenig zum verständnis meines anliegens bei, die anderen sachen habe ich natürlich als erstes probiert, und ein usb-hardware-analyzer mit dem ich bestimmte pakete einfach später nochmal betrachten kann steht mir nicht zur verfügung...
Aha. Das Debuggen wird interessant ;-) Der Trigger soll also nahe an den problematischen Befehlen platziert werden. Hier verschiedene Varianten... int main(void) { // deine Variante #1. Funktion entrollen // Nachteil: schlechte Wartung und ggf. problematisch zu machen // Vorteil: Trigger unmittelbar an den Befehlen triggerbefehl; befehl1; befehl2; // andere Variante #2. // Nachteil: ggf. Zeitproblem durch den Funktionsaufruf triggerbefehl; funktion1(); // andere Variante #3 // Nachteil: ggf. noch grösseres Zeitproblem durch 2 Funktionsaufrufe trigger(); funktion1(); // andere Variante #4 zu #2 // Verlagerung der Triggerung näher den Funktionsbefehlen // Nachteil: Abfrage in der Funktion beeinflusst auch // Zeitverhalten ungetriggerter Aufrufe triggerflag = TRUE; funktion2(); triggerflag = FALSE; } Mit folgenden Funktionen void funktion1(void) { befehl1; befehl2; } void funktion2() { if (trigger) triggerbefehl; befehl1; befehl2; } void trigger(void) { triggerbefehl; // ... ggf. mehrere Befehle } Variante 1 könnte für die kritische Funktion durch ein Makro implementiert werden: #ifdef MYDEBUG #define trigger() triggerbefehl #define funktion1() \ { \ int lokale_variable; \ befehl1; \ befehl2; \ } #else #define trigger() void funktion1(void) { befehl1; befehl2; } #endif /* MYDEBUG */ Innerhalb von main() ist der Code unverändert, bis auf den zusätzlichen Triggerbefehl int main(void) { ... trigger(); funktion1(); ... } dies wird bei gesetztem Makro MYDEBUG vom Präprozessor ersetzt durch: int main(void) { ... triggerbefehl; { int lokale_variable; befehl1; befehl2; }; ... } Die Klammerung ist wichtig wg. lokalen Variablen. Und bei nicht gesetztem Makro MYDEBUG durch int main(void) { ... ; funktion1(); ... } Ich könnte mich für Variante #4 erwärmen, wenn der minimale Overhead durch die Flagabfrage nicht stört.
danke für die ausführliche antwort stefan... bei den varianten 2-4 hast du recht, die sind alle samt ungünstig was den zeitfaktor angeht. deine makro-variante gefällt mir soweit ganz gut, hat aber für mich leider immer noch ein problem, das vll leider durch meine erklärung noch nicht ganz deutlich geworden ist. die triggerfunktion macht im grunde nichts anderes, als eine flanke zu erzeugen, die ich als trigger für den oszi nutze. ab dem punkt lese ich ich dann auf dem USB (auf der datenleitung) den verkehr mit und sehe mir an was so hin&her läuft. zeitlich ist das aber so kritisch, das man schon relativ genau "treffen" muss, damit die pakete noch im speicher des oszis sind. das problem ist einfach, dass ich den trigger-funktionsaufruf trigger() an verschiedene stellen in der untersuchten funktion packen können muss...du kannst dir die zu untersuchende funktion etwa so vorstellen void send_stuff() { send_paket1(); // <- mal trigger ich hier... //wait for response send_paket2(); //wait for response send_paket3(); //wait for response send_paket2(); //wait for response send_paket2(); // <- ...mal dort //wait for response send_paket1(); //wait for response } mir bringt es also leider nichts, wenn der trigger vor der funktion greift, ich muss ihn auch IN der funktion "verschieben" können. jetzt könnte ich das nat. mit deiner makro-variante machen, und im "MYDEBUG" teil bequem den trigger()-aufruf verschieben wie ich es will, ABER: dann habe ich das ja wieder für jeden aufruf der send_stuff - funktion, und im grunde nichts gewonnen !? deshalb schien mir das aufrollen, wenn auch extrem unübersichtlich weil der code so lang wird, am leichtesten, weil ich den trigger() einfach einmalig einfüge und der garantiert nie wieder aufgerufen wird, und ich nichts nebenher mitzählen muss (was sich vll gar nicht zählen lässt) puhh...viel zu lesen, ich hoffe ich konnte das problem halbwegs schildern ;-) beste grüße
Das ist dann doch nur eine Sache, wo du das Triggerflag positionierst und wo und wie es abgeprüft wird. Ich sehe das Problem mit dem Makro nicht. Du würdest ja deine send_stuff() Funktion so schreiben (angenommen du willst "mal dort" triggern): void send_stuff() { send_paket1(); // <- mal trigger ich hier... //wait for response send_paket2(); //wait for response send_paket3(); //wait for response send_paket2(); //wait for response trigger(); send_paket2(); // <- ...mal dort //wait for response send_paket1(); //wait for response } In obigem Fall würde ich also das Flag in send_stuff() an der entsprechenden Position vor der interessierenden send_paket*() Funktion setzen und dann in den send_paket*() Funktionen abprüfen und den Trigger erzeugen. Das Triggerflag muss auch nicht TRUE/FALSE sein. Du kannst mit verschiedenen Werten jeweils andere Codestellen triggern. Vielleicht sogar indem du den Wert für das Triggerflag über freien Input-Ports oder Schnittstellen manipulierst. Denkbar ist z.B. eine Triggerung auf die Rücksprungadresse auf dem Stack oder ganz bequem auf die aufrufende Sourcecodezeile (Stichwort _LINE_). Dazu würde die Anweisung triggerflag = ... durch eine triggersetz-Funktion z.B. über Ports oder einen seriellen Monitor ersetzt. Dann ist fürs Debuggen auch nicht jedesmal ein neuer Übersetzungslauf + das Einspielen auf den µC notwendig.
hmm, die kombination aus makro und flag klingt jetzt doch am sinnvollsten, da hast du absolut recht... ich setze mir im makro die trigger-funktion nebst flag-check einfach an die passende stelle und dann in der main() (oder wo auch immer) ab dem interessanten zeitpunkt das flag auf TRUE, ggf nutze ich einfach mehrere flags wenn es zu verschachtelt wird - das sollte dann eigentlich seinen zweck erfüllen und das gewünschte ereignis genau genug herausfiltern. ich werd' das einfach mal ausprobieren, vielen dank auf jeden fall für den denkanstoß und deine zeit... beste grüße
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.