Hallo µC-Bändiger!
Ich habe ein Programm für den AN2131 von Cypress geschrieben, dessen
Verhalten ich bisher (meistens zumindest) verstanden habe. Doch jetzt
passiert mir etwas sehr seltsames: Wenn ich folgende Funktion in meinem
Programm aufrufe, "spinnt" es, wenn die Variable zzz ein int ist, wenn
sie ein unsigned char ist, funktioniert es (zumindest scheint es so...)
1
chartest(){
2
unsignedcharxxx;
3
intzzz;
4
//unsigned char zzz;
5
xxx=4;
6
zzz=5;
7
return"a";
8
}
Liegt das Problem vielleicht in einer Art "Speicherüberlauf"?
Mit hoffenden Grüßen,
elko
Ähm, nein, das "a" hatte ich nur zu testzwecken eingesetzt... mit
"spinnen" meine ich, dass sich das Programm -soweit man das von außen
beurteilen kann- aufgehängt hat (wie windoof...)
grüße
Aber warum soll er sich in der Funktion bemerkbar machen, wenn sie doch
eigentlich nicht s macht und auch keine Daten von außen verwertet? Vor
allem: Wieso soll er auftreten, wenn zzz ein int ist und wenn zzz ein
char ist, tut er es nicht?!
Stefan S. schrieb:
> allem: Wieso soll er auftreten, wenn zzz ein int ist und wenn zzz ein> char ist, tut er es nicht?!
z.B. weil ein (lokaler) char oft nur 1 byte auf dem Stack benötigt, ein
int aber häufig 2 oder 4 bytes.
Eben genau deswegen verstehe ich nicht, warum der Fehler woanders im
Programm liegen soll: Tritt das Problem nur auf, wenn man char gegen int
austauscht, so vermut ich, dass das Problem ggf. an einem
Speicherüberlauf oder so etwas in der Richtung liegt... aber wie kann
ich das Problem lösen (falls es dies ist)?
Viele Grüße,
Stefan
a.) Welcher Compiler und welche Einstellungen?
b.) Wie oben schon geschrieben wurde, Rückgabewert und Deklaration
passen nicht zusammen.
c.) Wenn der Compiler nicht strunze-dumm ist und Optimierungen
eingeschlatet sind, werden die Zuweisungen ersatzlos weg optimiert da
sie nie benutzt werden.
d.) Wenn der Compiler nicht strunze-dumm ist und Optimierungen
eingeschlatet sind, wird die verbleibende Funktion komplett inlined,
weil sie trivial ist.
e.) Wie oben schon geschrieben: Das Problem sitzt in 99,9999% der Fälle
vor dem Computer und versucht den Compiler zu benutzen. Du hast irgendwo
anders im Programm in Bug.
f.) Wenn Du einen Fehler hast bei dem der C-Standart sagt, das Verhalten
ist undefiniert, darf der Compiler machen was er will, auch solche
lustigen Dinge wie Du beschreibst.
Fazit: Bring Deinen restlichen Code auf Vordermann. Vermutlich ist der
total verbugt.
Stefan S. schrieb:
> Ähm, nein, das "a" hatte ich nur zu testzwecken eingesetzt... mit> "spinnen" meine ich, dass sich das Programm -soweit man das von außen> beurteilen kann- aufgehängt hat (wie windoof...)
Woran erkennst Du, dass sich Dein Programm genau in dieser Funktion
aufhängt?
Experte schrieb:
> a.) Welcher Compiler und welche Einstellungen?
µVision3 von Keil
zu den Einstellungen kann ich um ehrlich zu sein kein Kommentar abgeben
(kenne mich nicht soooo gut mit dem Compiler aus und weis nicht, was du
meinst...)
> b.) Wie oben schon geschrieben wurde, Rückgabewert und Deklaration> passen nicht zusammen.
Auch wenn ich zB 5 zurückgebe, funktioniert das Programm nicht
> c.) Wenn der Compiler nicht strunze-dumm ist und Optimierungen> eingeschlatet sind, werden die Zuweisungen ersatzlos weg optimiert da> sie nie benutzt werden.> d.) Wenn der Compiler nicht strunze-dumm ist und Optimierungen> eingeschlatet sind, wird die verbleibende Funktion komplett inlined,> weil sie trivial ist.
Das denke ich nicht, denn Programsize ändert sich, wenn ich den Code in
der Funktion test() weglasse.
> e.) Wie oben schon geschrieben: Das Problem sitzt in 99,9999% der Fälle> vor dem Computer und versucht den Compiler zu benutzen. Du hast irgendwo> anders im Programm in Bug.
Da stimme ich dir zu... [ironie] aus dem Fenster spring = Problem
beseitigt [/ironie]
> f.) Wenn Du einen Fehler hast bei dem der C-Standart sagt, das Verhalten> ist undefiniert, darf der Compiler machen was er will, auch solche> lustigen Dinge wie Du beschreibst.
Meinst du wirklich, dass ein solches Verhalten auf "normale"
Programmierfehler zurückzuführen ist?
> Fazit: Bring Deinen restlichen Code auf Vordermann. Vermutlich ist der> total verbugt.
Das kann ich mir wiederum auch gut vorstellen... Ich würde auch das
ganze Programm nochmals überarbeiten, aber dazu wäre es sinnvoll, dass
ich den Programmablauf "live" mitverfolgen kann. Doch da in dem
Programm, das unter anderem 1en und 0en für ein
Onewire-Übertragungsprotokoll generiert, viele Schleifen vorhanden sind
(eben auf Grund der Erzeugung der verschieden langen 1en und 0en), ist
ein Debuggen meines erachtens sehr schwierig... hast du (oder jemand
anders) eine Idee, wie ich mehr Kontrolle über den Programmablauf
bekommen kann?
Viele Grüße,
Stefan
OK. Da du nicht begreifen willst und es anscheinend nicht reicht es dir
durch die Blume zu sagen:
*************************************************************
Wenn du hiernei Hilfe haben möchtest, dann poste den kompletten Code!
Dein Fehler sitzt nicht in dieser Funktion.
*************************************************************
Vergiss die Idee, dass der Compiler einen Fehler gemacht hat. Zu 99.9%
ist der Fehler immer im Programm. Nur Neulinge denken, dass sie mit
ihrem cleveren Code einen Compilerfehler entdeckt haben, den vor ihnen
noch nieeee irgendwer anderer gesehen hat. In Wirklichkeit sind es
meistens irgendwelche Array-Overflows, mit denen der Stack zerschossen
wird oder sonst irgendwelche banalen Dinge, wie zb Unverständnis wie
Stringverarbeitung in C wirklich funktioniert.
> Meinst du wirklich, dass ein solches Verhalten auf "normale"> Programmierfehler zurückzuführen ist?
Wenn du Sicherheit vor dir selbst haben willst, dann ist C die falsche
Sprache für dich. C funktioniert nach dem Muster: You asked for it, you
got it.
Nur so als Zwischenfrage: Besitzt du eigentlich ein C-Buch, welches dir
Schritt für Schritt beibringt, was du tun darfst, was nicht und wie man
bestimmte Dinge löst bzw. worauf man achten muss. Das ist nämlich der
nächste Fehler: zu glauben man könnte eine Programmiersprache ohne
vernünftige Literatur aus dem Stegreif lernen.
>> Fazit: Bring Deinen restlichen Code auf Vordermann. Vermutlich ist>> der total verbugt.> Das kann ich mir wiederum auch gut vorstellen... Ich würde auch> das ganze Programm nochmals überarbeiten, aber dazu wäre es> sinnvoll, dass ich den Programmablauf "live" mitverfolgen kann.
Das ist Quatsch.
Sinnvoll ist es, den Code in Funktionen aufzuteilen und sich an die
simple Weisheit zu halten: Eine Funktion soll nur das tun, was aussen
drauf steht. Ist die Funktionalität innerhalb der Funktion trivial, dann
bleibt die Funktion so. Ist sie komplexer, so wird auch diese Funktion
wieder in Unterfunktionen aufgeteilt, solange bis Funktionen kein
Spaghetticode mehr sind, sondern so übersichtlich, dass man sich durch
Hinschauen von der Korrektheit des Verfahrens überzeugen kann. Danach
(oder gleichzeitig) geht man jede Funktion durch und überzeugt sich
davon, dass alle Regeln der Sprache eingehalten wurden.
Dazu musst du dein Programm meistens noch nicht einmal laufen haben. Um
zu Prüfen, ob die Sprachregeln eingehalten wurden, ist Laufenlassen
sowieso der schlechteste Weg. Denn wie schon gesagt hat der Compiler
eine ganze Menge Spielraum und kann auch bei vielen Regelverletzungen
immer noch Code erzeugen, der auf den ersten Blick sauber läuft aber in
speziellen Situationen kläglich versagt. Ein gutes, korrektes Programm
fängt immer damit an, dass man sauberen Code hat. Und das fängt bei ganz
banalen formalen Dingen an: gute Variablennamen, saubere Einrückungen,
lesbarer Code. Wenn ich schon Variablennamen wie xxx und zzz sehe, will
ich mir lieber nicht vorstellen, wie der Rest vom Code aussieht.
Was auch immer hilfreich ist, ist den generierten Assembler-Code
anzusehen. Da sieht man dann genau, was der Compiler aus seinem Code
gemacht hat.
Wenn das Programm, wie in Deinem Fall (wenn es denn wirklich so ist),
hängen bleibt (Hängen ist immer eine Endlosschleife, bei der etwas
passiert, was nicht von aussen sichtbar ist), so hat zu 99% der
Stack-Pointer etwas damit zu tun. Denk dran, dass dieser nicht endlos
groß ist. Speziell bei rekursiven Aufrufen läuft der schnell über. Bei
einem PC gibt es hierzu Überwachungsroutinen, die Dich vorher warnen.
Ein µC hat solche Routinen nicht. Der PC springt dann womöglich irgendwo
hin und landet dann in einer Schleife.
Läuft der Stack über, fängt er normalerweise wieder unten an und
überschreibt entweder Programmvariablen oder auch wiederum den Stack
selber.
Kommt drauf an, wie der Prozessor das handhabt.
Es ist übrigens gut möglich, ein Assemblercode manuell (also auf dem
Papier/Editor) zu durchlaufen. Das machst Du für jede Funktion und
schreibst Dir die Speicherzustände mit (auch den PC und SP).
Karl heinz Buchegger schrieb:
> *************************************************************> Wenn du hiernei Hilfe haben möchtest, dann poste den kompletten Code!> Dein Fehler sitzt nicht in dieser Funktion.> *************************************************************
gerne. Ich will dir nichts vorenthalten, aber ich kann mir vorstellen,
dass das nicht einfach ein "drübergucken - da ist der Fehler!" wird...
aber ich will keine voreiligen Schlüsse ziehen ;-)
> Vergiss die Idee, dass der Compiler einen Fehler gemacht hat. Zu 99.9%> ist der Fehler immer im Programm. Nur Neulinge denken, dass sie mit> ihrem cleveren Code einen Compilerfehler entdeckt haben, den vor ihnen> noch nieeee irgendwer anderer gesehen hat.
das habe ich auch schon öfters festegestellt... Und ich bin mir sicher,
dass ich einen Fehler gemacht habe, aber WIESO kann es überhaupt
passieren, dass bei einer Änderung einer Variable von char zu int in
einer Funktion, die absolut NIE aufgerufen wird, eine Änderung des
Programmablaufes zur Folge hat???
> Nur so als Zwischenfrage: Besitzt du eigentlich ein C-Buch, welches dir> Schritt für Schritt beibringt, was du tun darfst, was nicht und wie man> bestimmte Dinge löst bzw. worauf man achten muss. Das ist nämlich der> nächste Fehler: zu glauben man könnte eine Programmiersprache ohne> vernünftige Literatur aus dem Stegreif lernen.
ich habe schon einige Bücher gewälzt (Grundlagen...) und verstanden
(okay, was man nicht täglich anwendet vergisst man... zB
Stringverarbeitung bei µC)
>>> Fazit: Bring Deinen restlichen Code auf Vordermann. Vermutlich ist>>> der total verbugt.>> Das kann ich mir wiederum auch gut vorstellen... Ich würde auch>> das ganze Programm nochmals überarbeiten, aber dazu wäre es>> sinnvoll, dass ich den Programmablauf "live" mitverfolgen kann.>> Das ist Quatsch.
denke ich nicht, denn dann könnte ich vielleicht endlich sehen, wo sich
das Programm "aufhängt" (oder sonstwas tut...
> Ein gutes, korrektes Programm> fängt immer damit an, dass man sauberen Code hat. Und das fängt bei ganz> banalen formalen Dingen an: gute Variablennamen, saubere Einrückungen,> lesbarer Code. Wenn ich schon Variablennamen wie xxx und zzz sehe, will> ich mir lieber nicht vorstellen, wie der Rest vom Code aussieht.
Darauf habe ich geachtet, nur nach stundenlangem Fehlersuchen und
zahlreichen vergeblichen Änderungen mache ich mir keine Gedanken, wie
ich Variablen in einer Funktion zu testzwecken nenne... (ein dreifaches
z baut die dreifache Menge an Agressionen ab ;-))
Wäre schön, wenn du mir nen Tipp geben kannst ;-)
Gruß,
Stefan
@ Christian: Ich werde demnächst auch mal versuchen, den Code nochmals
komplett zu überarbeiten
Karl heinz Buchegger schrieb:
> Wieviel Speicher hat das Ding?> Du allocierst du eine Menge Holz global
So arg viel ist es nicht. Das Teil hat effektiv knapp 7KB RAM und das
Program verbrät keine 400. Der Compiler platziert xdata zwar erst ab
0x800 und verschenkt damit 2KB, das ist aber letztlich immer noch egal.
Der explizit ab 0x0119 platzierte Variablenblock erschliesst sich mir
auch nicht, sollte aber ebenfalls dabei keine Rolle spielen.
Nur frage ich mich dann schon, welchen Sinn diese auf den ersten Blick
nicht sehr zum Controller passend scheinende Speicherverteilung und
dieser merkwürdig anmutendene Variablenblock haben. Ob da irgendwas quer
konfiguriert ist. Allerdings habe ich von der Doku des Controllers nur
ein paar Seiten quergelesen, vielleicht hat das ja einen Sinn.