Forum: Compiler & IDEs Structur in Funktion, merkwürdiges Ergebnis


von C-dummy (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
bin keine C-Leuchte, arbeite aber trotzdem damit.
Jetzt ist ein Problem aufgetaucht bei dem ich nicht weiter
komme. Zur Illustration habe ich einen screen-shot angehängt.

Ich verwende zwei Funktionen die ähnlich aufgerufen werden , in denen
dieselbe Structur benutzt wird (im Bild unten) . Der Aufruf ist auch
ziemlich gleich (im Bild oben). Das Ergebnis ist jetzt aber so, dass
der grün umrahmte Ausfruf der grün umrahmten Funktion funktioniert,
der rot umrahmte hingegen nicht. Im Bild rechts oben sieht man wie
der Inhalt der Structur aussehen sollte (gelb), und wie er ist (rot).
Bei der "grünen" Funktion stimmt alles prima überein. Die Adresse
der Structur in der roten Funktion ist aus irgend einem grund falsch.

Der Compiler ist GCCARM.

Kann mir bitte jemand sagen was ich hier falsch mache?

Danke

von Martin F. (martinf)


Lesenswert?

Mehr Quellcode wäre nicht schlecht. z.B. Zeilen 2000-2500 der Datei, 
welche die beiden Aufrufe tätigt.

von C-dummy (Gast)


Angehängte Dateien:

Lesenswert?

Danke für's ansehen.

Glaube nicht dass die Vorgeschichte was hilft. Es sind weitere 
Funktionen
die nichts mit dem Aufruf zu tun haben.

Aber bitte hier etwas mehr Code davor.

Gruss

von ozo (Gast)


Lesenswert?

Wie wärs mit Text statt Bildern?
Wo sind die Strukturen definiert?

von C-dummy (Gast)


Lesenswert?

In Bildern meine ich die Zusammehänge besser darstellen zu können.
Der Text sagt meiner Meinung nach fast weniger.

Hier die Struktur definition als Text

typedef struct PID_DATA{
  float f_lastProcessValue; //! Last process value, used to find 
derivative of process value.
  float f_sumError;         //! Summation of errors, used for integrate 
calculations
  float f_P_Factor;         //! The Proportional tuning constant, 
multiplied with SCALING_FACTOR
  float f_I_Factor;         //! The Integral tuning constant, multiplied 
with SCALING_FACTOR
  float f_D_Factor;         //! The Derivative tuning constant, 
multiplied with SCALING_FACTOR
  float f_maxError;         //! Maximum allowed error, avoid overflow
  float f_maxSumError;      //! Maximum allowed sumerror, avoid overflow
} pidData_t;


und


struct PID_DATA tdr1_pid_struct;
struct PID_DATA tdr2_pid_struct;


Danke für die Hilfe.

von C-dummy (Gast)


Lesenswert?

Vielleicht noch eine Bemerkung die eventuell von Bedeutung ist, aber auf 
den ersten Blick gar nichts mit dem struct Problem zu tun hat.

Die Parameter die ich beim Aufruf übergebe sind teilweise so definiert:

z.B. f_pid1_solltempdiff

typedef union _un_float_to_char {
  float  fVal;
  u_char  cVal[4];
}un_float_to_char;

un_float_to_char f_pid1_solltempdiff;

Normalerweise benutze ich die Variable so:

f_pid1_solltempdiff.fVal = 1.234;

Erst dachte ich beim Aufruf der Function mit dem struct Problem ich
müsste das so machen:

f_test = PID_Controller(f_pid1_solltempdiff.fVal, 
f_pid_tempdiff1_ist.fVal, &tdr1_pid_struct);

Das lieferte aber auch falsche Werte in der PID_Controller Funktion.

Nur so werden diese Parameter richtig übergeben:

f_test = PID_Controller(f_pid1_solltempdiff, f_pid_tempdiff1_ist, 
&tdr1_pid_struct);

Ist vielleicht ein anderes Problem, aber eventuell hilft es doch
meinen "Verhau" zu ordnen. Warum das so ist weiss ich als Autodidakt
leider nicht.

Gruss

von ozo (Gast)


Lesenswert?

Sorry, mir das jetzt alles zusammenzureimen übersteigt meinen 
Alkoholvorrat.
Falls du ein möglichst übersichtliches Codefragment, welches den Fehler 
immer noch zeigt, einstellen würdest, würden sich deine Chancen auf 
Hilfe erheblich verbessern...
Ansonsten mal so in Blaue: Stack kaputt?

Gruss

von Martin F. (martinf)


Lesenswert?

Werden tdr1_pid_struct und tdr2_pid_struct lokal in tdr.c definiert?
Wenn beide hintereinander definiert werden, dann vertausch mal die 
Reihenfolge. Kann es sein, dass der RAM nicht reicht? Obwohl du 
&tdr2_pid_struct an PID_Controller(...) übergibts, zeigt diese nämlich 
auf NULL.

von C-dummy (Gast)


Lesenswert?

Martin,

ja, werden sie.

Habe sie testhalber vertauscht, aber leider selbes Ergebnis. Habe
auch den Stack verdoppelt auf 0x1000 Byte(!), ohne Erfolg. Benutze
einen LPC2148 mit 32+2 K RAM. Sind ca. 4K RAM belegt. Sollte eigentlich 
vorerst reichen.

Danke und Gruss

von Martin F. (martinf)


Lesenswert?

Mach mal direkt am Anfang von PID_Controller(...) ne Abfrage für pid 
rein. z.B.:
1
float PID_Controller( ...) {
2
    if( !pid) {
3
        // Fehlerausgabe
4
    }
5
    float ....
6
}


Wenn da kein Fehler kommt, dann liegts am Debugger. Vielleicht kennt er 
den Wert von pid noch nicht und nimmt deshalb NULL als Adresse. Einfach 
mal weiter unten in der Funktion nen Breakpoint setzen.

von C-dummy (Gast)


Lesenswert?

Danke Martin.

Wäre ne Idee, aber ich weiss , dass es der Debugger nicht ist.
Die PID_Controller Funktion wird nämlich nicht komplett durchlaufen,
sondern endet etwas später in einem BUSERROR Trap. Dadurch habe ich
es erst gemerkt, dass da was nicht stimmt.

Habe deinen Vorschlag dennoch ausprobiert. Der Fehlerdurchlauf war wie
erwartet da.

Gruss

von C-dummy (Gast)


Angehängte Dateien:

Lesenswert?

Sorry, wieder ein Bild.

Habe mal bei Aufrufe testhalber von der Parameteranzahl gleich
gemacht und den Assembler Code beider Aufrufe angezeigt. Aus irgend
einem Grund sind beide Aufrufe total unterschiedlich umgesetzt.

Einziger Unterschied beim Aufruf ist der eine gezeigte Parameter der
nicht durch typedef union definiert ist.

Gruss

von C-dummy (Gast)


Lesenswert?

Vergessen,

da ändert sich auch nichts dran wenn die PID-Conntroller Funktion
so umgebaut ist, dass sie nichts zurück liefert.

von (prx) A. K. (prx)


Lesenswert?

Im letzten Fall wird der zweite Parameter als "double" übergeben, im 
Thread liegt aber als Deklaration der Funktion (aus dem ersten 
Screenshot) nur eine Version vor, die dort "float" erwartet. Und das 
Resultat wird von "int" nach "float" konvertiert. Wie soll man damit was 
anfangen? Wie soll man den Assembler-Code eines Aufrufs bewerten, dessen 
aktuelle Deklaration man nicht kennt? Die Datentypen der Variablen 
ebensowenig.

von C-dummy (Gast)


Lesenswert?

Ich benutze hier (wissentlich) keine double.

So sind die Variablen global declariert:

typedef union _un_float_to_char {
  float  fVal;
  u_char  cVal[4];
}un_float_to_char;


//---------------------------
float f_pid_tempdiff1_ist;
float f_pid_tempdiff_ist;

float f_pid_diff;
float f_pid_solltempdiff;

un_float_to_char f_p1_factor_set;
un_float_to_char f_i1_factor_set;
un_float_to_char f_d1_factor_set;

un_float_to_char f_pid1_solltempdiff;

struct PID_DATA tdr1_pid_struct;


Reicht das ?

Vielen Dank

von C-dummy (Gast)


Lesenswert?

Das Problem ist gelöst!

Ich bekam einen Tip von einem Bekannten, der schon mal ein
ähnliches Problem hatte. Er riet mir die PI-Controller Funktionen
komplett zu kopieren und an einem anderen Ort mit anderem Namen
nochmals zu platzieren und dann diese Funktion aufzurufen.

Im zweiten Anlauf bekam ich dann die "erhofften" Fehlermeldungen
des Compiler bezüglich der fVal bei den Parameteraufrufen. Und
schon hat es funktioniert. Nach weitern Untersuchungen kam ich
dann drauf, dass die ursprüngliche Funktion auch richtig arbeiten,
wenn ich sie im "Hauptprogram" als extern deklariere. Das hatte ich
wohl übersehen. Also mit anderen Worten, sind die PID_xxx Funktionen
als extern nicht dekariern , mecckert der Compiler nicht , aber geht
auch nicht. Sind die PI_xxx Funktionen als extern delariert, meckert der
Compiler auch nicht (soll er auch nicht) , aber es funktioniert wie 
gewünscht.

Danke Stefan für den sehr hilfreichen Tip.

Danke auch an alle die sich Zeit für mein Problem genommen und versucht
haben mir zu helfen.

Gruss

von yalu (Gast)


Lesenswert?

> Also mit anderen Worten, sind die PID_xxx Funktionen als extern nicht
> dekariern , mecckert der Compiler nicht , aber geht auch nicht.

Der Compiler braucht den Funktionsprototypen, um zu wissen, dass die
aufgerufene Funktion float-Argumente erwartet. Weiß er dies nicht,
übergibt er die Argumente als double, was zur Laufzeit für Verwirrung
sorgt.

Mit der Option -Wimplicit warnt der Compiler vor fehlenden Prototypen,
deswegen sollte diese Warnung für selbstgeschriebene Programme immer
eingeschaltet sein. Noch besser ist es, -Wall anzugeben. Diese Option
schließt -Wimplicit mit ein und warnt zusätzlichen vor vielen weiteren
gefährlichen Konstrukten. Man erspart sich damit — wie auch in deinem
Fall — viel Ärger für die Fehlersuche :)

von C-dummy (Gast)


Lesenswert?

Danke für den Hinweis, wußte ich natürlich nicht.

Habe -Wall im Makefile eingebaut.

Gruss

von C-dummy (Gast)


Lesenswert?

-Wall ist wirklich der Hammer!

Da habe ich heute viel gelernt (und einige Zeit aufwenden müssen
alles wieder gerade zu biegen)!

Man sieht auch was der Compiler eigentlich so quasi tolleriert und
implizit annimmt. Oft ist es ok, manchmal aber doch eher nicht. Man
sieht weiter, dass manche Experten (paar SW-Teile habe ich mir
ausgeliehen) es auch nicht so genau nehmen!

Danke nochmals für den Tip.

Gruss

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.