Übergabe von Strukturen mit Pointern
-
Hallo,
ich schreibe mit MinGW eine kleine Konsolenanwendung, die ihre eigene exe rekursiv aufruft. Dabei muss ich aber die Daten aus einer Struktur in allen Programminstanzen haben. Meine erste Idee war, die Daten in einer Datei zwischenzuspeichern und diese in jeder Instanz neu einzulesen. Die Struktur enthält aber auch ein Pointer-Array auf Daten, die außerhalb der Struktur liegen. Gibt es eine Möglichkeit, so ein Kontrukt komplett in einer Datei zu speichern und wieder einzulesen? Oder gibt es vielleicht eine andere Möglichkeit, wie ich die Daten übergeben kann?
Gruß, Heimchen
-
Du musst eben das, worauf gezeigt wird, auch mit abspeichern. Was du suchst ist wohl irgendein Dateiformat. Je nachdem, wie kompliziert deine Strukturen sind, kann das zum Beispiel eine einfache Liste der Datenelemente, durch Trennzeichen getrennt, sein oder auch komplexe Formate wie etwas XML-basiertes, mit dem man auch komplizierte, verschachtelte Strukturen abbilden kann.
Jedoch:
heimchen schrieb:
ich schreibe mit MinGW eine kleine Konsolenanwendung, die ihre eigene exe rekursiv aufruft.
Dies hier ist super ungewöhnlich und ungeschickt. Wozu sollte man jemals so etwas benötigen? Das macht gar keinen Sinn. Erklär mal. Was du vor hast geht anders garantiert 100x besser und einfacher.
-
Hab noch einen zweiten Thread, da geht es um Modultests. Da ist leider bis jetzt nur die Variante herausgekommen.
Ich schreibe ein Modultest, der meine Komponente in ihrem Zustand nach einem Reset testen soll. Meine erste Idee war, den RAM-Bereich der Testkomponente separat festzulegen und neu zu initialisieren (so hätt ich es auf einem µC gemacht). Das stieß auf wenig Gegenliebe hier. Das Resultat war eben genau das, dass ich einfach eine neue Instanz des Testprograms erzeuge und darin den Test ausführe. Die Test-Suite (aktuell CuTest) und den Index des auszuführenden Testruns würde ich beim Aufruf übergeben. Und genau die Testsuite ist das Problem. Die enthält Pointer auf die Testfälle und Strings (also char[]). Und das Ergebnis wird ebenfalls in die Suite bzw. den Testfall zurückgeschrieben.
Eine andere Variante wäre, das ganze ohne den Umweg über eine Datei zu übergeben, aber da weiß ich nicht, wie.
-
Solltest du dann nicht das zu testende Programm durch ein anderes Programm ausführen? Wenn das zu testende Programm sich inklusive des Tests selber aufruft, dann macht der Testcode doch kaputt, was du erreichen möchtest. Ebenso die Runtime Library selber, falls dein zu testendes Programm eine haben sollte, wodurch das ganze Vorhaben ohnehin unmöglich wäre.
Ansonsten: Interprozesskommunikation. Dass du anscheinend in Datenfelder eines anderes Prozesses schreiben möchtest, klingt sehr, sehr wild. Das funktioniert so nicht. Oder verstehe ich dich gerade falsch?
-
Die eine Variante wäre, ich schreibe in die Daten eines anderen Prozesses. Die andere Variante wäre, ich übergebe den Testcase und bekomme ihn geändert zurück.
Das ganze soll für den Testprogrammierer möglichst einfach gehalten sein. Zwei Programme heißt ja auch zwei Mal programmieren, compilieren, etc. Im Prinzip mahce ich aber die beiden Schritte nur in eins: wird mein Programm ohne Parameter aufgerufen, verhält es sich wie das Tastprogramm. Wird es mit Parametern aufgerufen, verhält es sich wie das zu testende Programm. Aber unabhängig davon hab ich immer das gleiche Problem...
Wenn es eine bessere Lösung gibt, nehm ich auch die. Ich hab bisher aber keine.
-
heimchen schrieb:
Die eine Variante wäre, ich schreibe in die Daten eines anderen Prozesses.
Ganz schlecht. Sowas macht man nicht. Auch nicht für Tests.
heimchen schrieb:
Die andere Variante wäre, ich übergebe den Testcase und bekomme ihn geändert zurück.
Verstehe ich nicht.
heimchen schrieb:
Das ganze soll für den Testprogrammierer möglichst einfach gehalten sein.
Ein Tester soll nicht programmieren (müssen).
heimchen schrieb:
Zwei Programme heißt ja auch zwei Mal programmieren, compilieren, etc.
Ganz schlecht.
Ein Compilat, das durch Konfiguration im Test- bzw. Produktionsmodus läuft.
-
Der Beritrag ist wahnsinnig zielführend:
Wutz schrieb:
heimchen schrieb:
Die eine Variante wäre, ich schreibe in die Daten eines anderen Prozesses.
Ganz schlecht. Sowas macht man nicht. Auch nicht für Tests.
-> Ich suche ja nach einer Alternative dafür. Mal abgesehen davon gibt's Shared Memory ja nicht umsonst. Kommt also eher auf den Anwendungsfall an...
Wutz schrieb:
heimchen schrieb:
Die andere Variante wäre, ich übergebe den Testcase und bekomme ihn geändert zurück.
Verstehe ich nicht.
Ich übergebe Daten (in meinem Fall ein Testcase) per Referenz und das aufgerufene Modul schreibt sein Ergebnis in die Referenz.
Wutz schrieb:
heimchen schrieb:
Das ganze soll für den Testprogrammierer möglichst einfach gehalten sein.
Ein Tester soll nicht programmieren (müssen).
-> Wie automatisiert man denn sonst Tests? Es gibt Firmen, die nur Testwerkzeuge herstellen, die programmiert werden müssen. Hab gehört, die leben ganz gut davon.
Wutz schrieb:
heimchen schrieb:
Zwei Programme heißt ja auch zwei Mal programmieren, compilieren, etc.
Ganz schlecht.
Ein Compilat, das durch Konfiguration im Test- bzw. Produktionsmodus läuft.-> Wer hat denn ein Compilat, dass einen Testmodus hat?
Ich habe ein Problem, zu dem ich eine Lösung suche. Ich möchte nicht wissen, wie schlecht mein Modul ist oder was man macht oder nicht. Ich möchte wissen, wie ich ein Modul mehrfach hintereinander in einen Zustand versetzen kann, der dem nach einem Reset entspricht, um diesen zu testen. Ich kann auch hergehen, mein Projekt auf den µC laden und per Debugger testen. Da kann ich Resets machen und Daten manipulieren. Will ich aber nicht. Ich will's automatisiert.
Ich hab mich mal ein wenig in Interprozesskommunikation eingelesen. Leider enthält das Beispiel nur das Händling für Strings. Wenn ich meine Test-Suite-Struktur z.B. in einen Shared-Memory ablegen würde, käme das dem was ich will schon sehr nahe. Aber wie mach ich das? Wie gesagt, da drin sind auch Pointer z.B. auf Strings, etc.
-
Um mal sicher zu gehen, dass ich dich korrekt verstanden habe: Das was du hier testest, das wird einmal für x86 (oder andere typische PC-Hardware) als eigenständige Desktopanwendung übersetzt und einmal für den µ-Controller? Also auf der PC-Hardware nicht irgendwie emuliert, sondern wirklich selbstständig?
Falls ja: Dann ist der Test, den du hier vor hast, doch ohnehin völlig aussagefrei und somit zwecklos. Der Start einer Anwendung in einem hgalbwegs normalen Betriebssystem läuft schließlich ganz anders ab als auf dem µ-Controller und hinterlässt gänzlich andere Spuren. Falls nein: Dem Emulator kann man doch sicher aus beibringen, ein Reset zu emulieren.
-
Der Code, den ich teste, läuft später auf einem µC. Für den Test hab ich ihn allerdings in ein MinGW C-Projekt gepackt, es ist aber der gleiche Code. Der Grund ist recht einfach: es ist für mich viel einfacher, ein neues MinGW Projekt anzulegen, als ein neues Controller-Projekt, dass ich dann auf meinen Code reduziere. Einen reinen Code-Emulator hab ich leider nicht. Eine Alternative wäre noch, ich würde die Schnittstellen aus meinem Projekt entfernen und mit meinem Testmodul bedaten, aber alles in allem immernoch deutlich aufwändiger. Ich habe auch eine Testumgebung, die auf dem Debugger läuft, aber die ist sehr aufwändig und in einigen Fällen auch umständlich zu programmieren. Dort kann ich zum Beispiel nicht einfach in einer Schleife einen ganzen Wertebereich durchlaufen lassen oder eine Routine x Mal aufrufen.
Die "Gleichheit" stelle ich über eine Abstraktionsebene her, die ich sowieso schon habe. So verwende ich auch keine Compiler-Typen sondern immer selbst definierte Typen. Und die Deklaration unterscheidet sich dann auch zwischen µC und PC. Funktional dürfte sich dadurch nichts ändern. Natürlich muss ich in meiner Testumgebung sicherstellen, dass das auch so ist. Aber das ist für mich das geringere Übel...
-
heimchen schrieb:
Funktional dürfte sich dadurch nichts ändern. Natürlich muss ich in meiner Testumgebung sicherstellen, dass das auch so ist. Aber das ist für mich das geringere Übel...
Na, da bin ich mal gespannt. Wenn du schon Probleme mit der Serialisierung einfacher Datenstrukturen hast, wie soll dann das gleichartige Verhalten von Executables beim Start für dich ein kleines Übel sein? Irgendwie glaube ich dir das nicht. Ich habe fast den Verdacht, dir ist überhaupt gar nicht klar, was das Problem ist. Warum gibt folgender Code nicht 0 aus?
http://ideone.com/X49QOi
Der Speicher wird vom Betriebssystem genullt, bevor er an einen Prozess übergeben wird. Die Binärdarstellung einer Integer Null ist ebenfalls 0 (zumindest bei der Hardware, die ideone benutzt). Woher kommt also die 2? Wieso ist das jedes Mal 2, auch wenn du das Programm erneut ausführst? Wieso ist das nicht unbedingt 2, wenn du das Programm auf einem anderen System ausführst (bei mir ist es zum Beispiel 32760)? Wieso ist es nicht mehr 2, wenn du andere Compiler oder andere Compileroptionen wählst (ideone optimiert nicht. Optimiere ich bei mir, bekomme ich 32621)?
-
Ist ein anderes Thema. Zum einen würde in dem Fall mein Testcase fehlschlagen und ich wüsste, dass ich was zu tun hab. Zum anderen wird bei uns z.B. per MISRA-Check geprüft, dass alle Variablen initialisiert werden, um genau solche Probleme zu verhindern.
Das hat aber nicht wirklich was mit meinem Problem zu tun. Das Ding ist doch, dass ich aktuell nicht in der Lage bin, den zu testenden Code vor einem Testfall wieder in seinen Ursprungszustand zurückzuversetzen. Und dafür suche ich eine Lösung - wie auch immer die aussehen mag.
BTW: auf der Zielhhardware müsste ich den RAM-Bereich des Moduls neu initialisieren bzw. um es wirklich richtig zu machen den Controller manuell resetten. So ganz trivial ist das auch dort nicht und von Automation wär ich auch recht weit entfernt. Da wäre es schon ein riesen Schritt, es würde auf dem PC testbar sein.
-
heimchen schrieb:
Ist ein anderes Thema.
Ist das nicht genau das Thema?
Lass die Variablen initialisiert sein, aber der Code hat einen Fehler:
#include <stdio.h> int main() { int j[10000] = {0}; printf("%i\n", j[10000]); return 0; }
Hier spielt doch die genaue Plattform hochgradig eine Rolle, was das Testergebnis sein wird. Sind im RAM nur Nullen? Falls ja, warum? Falls nein, warum nicht? Ist der Speicher segmentiert? Wenn ja, wie? Hochgradig plattformabhängig und, wie das vorherige Beispiel zeigte, durchaus etwas, was auf der PC-Plattform ganz anders ist als es (vermutlich) auf dem µ-IC sein wird*. Mir scheint, entweder hast du falsch dargestellt, was du überhaupt testen möchtest, oder dein Testverfahren ist an sich ungeeignet.
Das hat aber nicht wirklich was mit meinem Problem zu tun. Das Ding ist doch, dass ich aktuell nicht in der Lage bin, den zu testenden Code vor einem Testfall wieder in seinen Ursprungszustand zurückzuversetzen.
Was ist denn dann das Problem? Wenn du Fehler durch undefiniertes Verhalten angeblich ohnehin schon findest, dann ist doch das restliche Verhalten bei Wiederaufruf des Codes genau definiert.
BTW: auf der Zielhhardware müsste ich den RAM-Bereich des Moduls neu initialisieren bzw. um es wirklich richtig zu machen den Controller manuell resetten. So ganz trivial ist das auch dort nicht und von Automation wär ich auch recht weit entfernt. Da wäre es schon ein riesen Schritt, es würde auf dem PC testbar sein.
Mir scheint, du bräuchtest einen Emulator.
*: Ich habe den Eindruck, es ist immer noch nicht angekommen: Eine Executable in einem normalen PC-Betriebssystem fängt zwar mit resettetem Speicher an, aber schon allein dadurch, dass es eine Executable in einem normalen PC-Betriebssystem ist, passieren da bei Programmstart(!) schon tausend Sachen, die Spuren im Speicher hinterlassen. Diese Spuren sind hochgradig abhängig von der genauen Plattform und ihre Auswirkungen sind hochgradig abhängig von kleinsten Details des erzeugten Maschinencodes.
Das Verhalten von C-Programmen ist eben nur so weit portabel, wie das C-Programm korrekt geschrieben ist und kein undefiniertes Verhalten verursacht. Also was ist das Problem beim Testen? Entweder willst du Probleme durch undefiniertes Verhalten finden, dann ist der Test ungeeignet, bzw. der "Reset" unnötig. Oder das Programm ist an sich erst einmal korrekt, dann kannst du den Code doch einfach ausführen, um seine Funktion zu testen und ich verstehe nicht, was diese Frage über das Zurücksetzen des Codes soll.
-
Ok, vielleicht ist deine Vorstellung von meinem zu testenden Modul etwas zu komplex. Es enthält folgende Deklaration:
static uint8 state = 0u;
Eine zyklische Funktion in dem Modul führt nun einige Initialisierungsschritte durch und zählt dabei diese Variable hoch, bis das Modul initialisiert ist. Sagen wir, die Variable steht dann bei 255. Die Schnittstellenfunktionen meiner Komponente überprüfen bei ihrem Aufruf nun, ob diese Variable auf 255 steht. Wenn nicht, wird ein Fehler zurückgegeben.
Dieses Verhalten ist bei dieser Art von Code hoffentlich auf jedem System identisch. Ansonsten hätte eine standartisierte Programmiersprache ja keinen Sinn.
Ich möchte nun einfach vor meinem Test die Variable state wieder auf ihren Initialwert setzen, hier also 0. Aus meinem Testmodul heraus kann ich das aber nicht tun, da die Variable ja static ist. Darum die Geschichte mit dem "Zustand wie nach einem Reset" (damit meine ich nach dem start-up Code der z.B. das µC-RAM initialisiert).