Mein CCE ärger mich gewaltig.
Immermal wieder gehen bestimmte Funktionen nicht mehr.
Jetz macht sprintf nicht mehr das, was es soll. Es hat bis vor kurzem
funktioniert.
Ich möchte mehrere uint16-Werte in einen String speichern, aber dann
steht im String nur wirres Zeug.
Mark, sei nicht so garstig mit dem armen CCE! Ich behaupte, man kann mit
jedem Compiler ein Programm um deine Zeile produzieren, das die
beschriebenen Fehler erzeugt. Beste Voraussetzungen dafür sind wenig
freier RAM, d.h. zu Ende gehender Stack und falsch oder am falschen Ort
definierte Variablen.
Hi,
auf einem Controller mit begrenztem Speicher wie beim MSP430 sollte man
solch vergleichsweise großen Speicherbereiche wie bei deinem Fall auf
jeden Fall mit malloc reservieren!
Über den Rückgabe-Wert sieht man dann auch gleich, ob der Speicher
überhaupt zur Verfügung steht!
Ansonsten schließe ich mich meinem Vorredner an: Das sieht einfach
danach aus, dass du dein RAM nicht richtig nutzt und deshalb an
irgendwelchen wirren Orten schreibst und ließt, an denen du eigentlich
nicht sein solltest!
Das Problem hatte ich auch mal, seitdem speichere ich solche
Datenstrings im Flash.
Gruß,
Markus
markus schrieb:> Hi,>> auf einem Controller mit begrenztem Speicher wie beim MSP430 sollte man> solch vergleichsweise großen Speicherbereiche wie bei deinem Fall auf> jeden Fall mit malloc reservieren!
Und was bringt das?
Wenn der Speicher zu Ende ist, dann ist er zu Ende. Egal ob globale
Variable oder dynamisch allokiert.
> Über den Rückgabe-Wert sieht man dann auch gleich, ob der Speicher> überhaupt zur Verfügung steht!
Das du dich da mal nicht täuscht.
Typisch liefert malloc noch lange gültige Pointer, während der Heap
schon langst in den Stack hineingewachsen ist.
Bei IAR kann ich die Stackgröße angeben und die liegt default bei 80
Byte. Du könntest versuchen deine Variable buf als static außerhalb der
Funktion zu deklarieren, das wäre erst einmal das einfachste.
---
Es lag nicht am Speicher, Problem ist gelöst: stdio war nicht
inkludiert. Ich dachte, es reicht ein include in der main.c.
Aber warum kam denn keine Warnung vom Compiler?
Mark M. schrieb:> Warum wird der Monat nicht richtig formatiert?
Weil sprintf davon ausgeht das es eine 16Bit Variable uebergeben
bekommt.
Caste mal (uint16_t)mon in deinem Aufruf.
Mark M. schrieb:> Helmut Lenzen schrieb:>> Weil sprintf davon ausgeht das es eine 16Bit Variable uebergeben>> bekommt.>> ??? Aber bei sek, min und day geht es doch auch?
Außerdem funktionierts auch mit dem Casten nicht.
Helmut Lenzen schrieb:> Weil sprintf davon ausgeht das es eine 16Bit Variable uebergeben> bekommt.
Das bekommt es auch, bei Funktionen mit variabler Argumentenliste wird
automatisch erweitert:
> Since the prototype doesn't specify types for optional arguments,> in a call to a variadic function the /default argument promotions/> are performed on the optional argument values.> This means the objects of type char or short int (whether signed> or not) are promoted to either int or unsigned int, as appropriate;> and that objects of type float are promoted to type double.
(Quelle:
http://www.gnu.org/s/libc/manual/html_node/Calling-Variadics.html#Calling-Variadics)
Im Beispiel aber wird nicht nur für den Monat, sondern auch für den Tag
was falsches ausgegeben, da geht also irgendwas anderes schief.
Sind die im Beispiel angegebenen Werte mit einem Debugger ermittelt
worden oder wo kommen die her?
Rufus Τ. Firefly schrieb:> Im Beispiel aber wird nicht nur für den Monat, sondern auch für den Tag> was falsches ausgegeben, da geht also irgendwas anderes schief.
Ups, sorry, hatte mich mal wieder vertippt! In buf steht natürlilch:
\r\n10 522 2011 15:55:02 1024 1024 0 128
> Sind die im Beispiel angegebenen Werte mit einem Debugger ermittelt> worden oder wo kommen die her?
Ja, die Werte hab ich aus dem Debugger, nachdem sie von der microSD
gelesen worden. Anschließend schreibe ich den Timestamp zusammen mit dem
Messdaten wieder auf die Karte und dann steht dort auch: 10 522 2011
15:55:02 1024 1024 0 128
Bin mir gerade nicht sicher, aber werden bei sprintf die Argumente nicht
als Pointer übergeben? d.h. bei %u liest er 16 bit ab der angegebenen
Adresse. Die 522 sind ja 512+10, also lo-byte=10 und hi-byte=2, sieht
also so aus als ob hier das mon- und das day-byte ausgelesen werden.
Dass es bei min und sek funktioniert könnte daran liegen dass der
Compiler die Variablen umsortiert und dort "zufällig" 0-Bytes dazwischen
liegen...
Wenn Dein sprintf sowas hat nimm statt %u ein Format welches nur 1 Byte
liest; oder sonst müssen alle Variablen als uint16 deklariert sein.
Ok, ich hab jetzt alle Variablen, die nicht 16bit sind, nach uint16_t
gecastet und jetzt läuft es.
Danke, ich wusste nicht, dass sprintf 16bit erwartet. Ich hatte mir aber
eigentlich gedacht, dass es trotzdem funktionieren müsste, wie rufus
schrieb.
Mark M. schrieb:> Ich hatte mir aber> eigentlich gedacht, dass es trotzdem funktionieren müsste, wie rufus> schrieb.
Haengt wohl von der Compiler Version ab. Bin da auch schon mal drauf
reingefallen.
Mathias A. schrieb:> Bin mir gerade nicht sicher, aber werden bei sprintf die Argumente nicht> als Pointer übergeben?
O nein. Das werden sie nur bei den /scanf/-Varianten.
Mark M. schrieb:> Danke, ich wusste nicht, dass sprintf 16bit erwartet.
Dann solltest Du mal die Dokumentation Deines Compilers zum Thema
"default argument promotion" befragen.
Rufus Τ. Firefly schrieb:> Mathias A. schrieb:>> Bin mir gerade nicht sicher, aber werden bei sprintf die Argumente nicht>> als Pointer übergeben?>> O nein. Das werden sie nur bei den /scanf/-Varianten.
stimmt, da hast Du recht...sorry, weiß auch nicht mehr wie ich darauf
kam, zumal wenn es pointer wären ja eher das im Speicher hinter dem
mon-Feld liegende year statt dem day genommen worden wäre...bei Übergabe
übern Stack passt es ja dann wieder zu meiner Theorie, da dann day ja
hinter mon liegt. :)
Bei Pointern hätte auch der Typecast nichts genützt...
Wundert mich aber dann warum es bei min und sek trotzdem geklappt hatte,
aber nun gut, wenn es jetzt funktioniert sollte man vielleicht nicht
mehr zuviel Gedanken drüber verschwenden.
Mark M. schrieb:> Danke, ich wusste nicht, dass sprintf 16bit erwartet.
das hängt von der Plattform ab: allgemein liest %u ein "unsigned int",
was je nach Plattform eben 16, 32, 64 oder wieviel auch immer Bits sein
können. Dazu gibts normalerweise Modifier, z.b. %hu für unsigned short,
%lu für long, etc. Ist schon lange her dass ich sowas auf einem
16-Bit-System gemacht habe, aber wenn ich mich recht erinnere könnte %hu
das passende für 8-Bit-Werte sein (müsstest mal in der Doku Deines
Compilers/C-Lib nachschauen).
Mathias A. schrieb:> Wundert mich aber dann warum es bei min und sek trotzdem geklappt hatte,
Weil das nächste Byte im Speicher das als Highbyte eingelesen wurde
zufällig mit 0 besetzt war.
Helmut Lenzen schrieb:> Weil das nächste Byte im Speicher das als Highbyte eingelesen wurde> zufällig mit 0 besetzt war.
Das kommt mir spanisch vor. Angenommen, es sei so, wie Du annimmst, dann
müssten die Argumente nacheinander auf den Stack gepackt werden, ohne
die von mir angesprochene default argument promotion sollte das bei
den ersten sechs Argumenten day, mon, year, std, min, sek in folgenden
sieben Bytes resultieren:
10, 2, --2011--, 15, 55, 2
0x0A 0x02 0x07 0xDB 0x0F 0x37 0x02
oder (falls der Kram andersherum auf den Stack gepackt wird)
0x02 0x37 0x0F 0xDB 0x07 0x02 0x0A
Das aber haut vorne und hinten nicht hin, denn da fehlen die von Dir
angesprochenen zufälligen Nullen.
Für die ersten drei Formatspezifzierer müsste dann das hier
herauskommen:
0x0A02 522(!)
0x07DB 2011
0x0F37 3895
... was es ja nicht tut (resp. tun soll), es sollen ja alle Werte bis
auf den zweiten korrekt ausgegeben werden.
Auffällig ist hier allerdings der Wert 522, der kommt irgendwie
bekannt vor.