Forum: Compiler & IDEs s(n)printf führt zum HW-Fault


von Jo (Gast)


Lesenswert?

Hallo zusammen,

bin  hier etwas am Rästeln und ich hoffe ihr könnt mir Tipps zur 
Fehlersuche geben.
Bei Verwendung von der Funktion s(n)printf (snprintf(str,64,"%f",d);) 
springt mein STM32L1xx-Controller in den HW Fault. Aber nur an einer 
Stelle des Codes bzw. der Programmausfühung. Stelle ich zum Beispiel 
gleich zu Beginn in der Main() die Randbedingungen nach wird die 
s(n)printf-Funktion richtig ausgeführt.
Zielspeicher ist vorhanden
Näher kann ich das Fehlerbild leider nicht beschreiben ...  Sehe ja 
nicht, was passiert.

Was für Randbedingungen können denn Vorliegen, dass die 
s(n)printf-Funtkion abstürzt? Stack/Heap/... !?

Danke & Grüße
Jo

von coder (Gast)


Lesenswert?

Jo schrieb:
> Näher kann ich das Fehlerbild leider nicht beschreiben ...
...deshalb wäre etwas mehr Quelltext hilfreich

Jo schrieb:
> Sehe ja
> nicht, was passiert.
Debugger? ...oder einfach mal d vor dem snprintf irgendwo ausgeben...

von Jo (Gast)


Lesenswert?

coder schrieb:
> deshalb wäre etwas mehr Quelltext hilfreich
1
/* Render the number nicely from the given item into a string. */
2
static char *print_number(cJSON *item,printbuffer *p)
3
{
4
  char *str=0;
5
  double d=item->valuedouble;
6
  if (d==0)
7
  {
8
    if (p)  str=ensure(p,2);
9
    else  str=(char*)cJSON_malloc(2);  /* special case for 0. */
10
    if (str) strcpy(str,"0");
11
  }
12
  else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
13
  {
14
    if (p)  str=ensure(p,21);
15
    else  str=(char*)cJSON_malloc(21);  /* 2^64+1 can be represented in 21 chars. */
16
    if (str)  sprintf(str,"%d",item->valueint);
17
  }
18
  else
19
  {
20
    if (p)  str=ensure(p,64);
21
    else  str=(char*)cJSON_malloc(64);  /* This is a nice tradeoff. */
22
    if (str)
23
    {
24
      if (fpclassify(d) != FP_ZERO && !isnormal(d))        snprintf(str,64,"null");
25
      else if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)  snprintf(str,64,"%.0f",d);
26
      else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)          snprintf(str,64,"%e",d);
27
      else                            snprintf(str,64,"%f",d);
28
    }
29
  }
30
  return str;
31
}

Von Malloc zurückgelieferte Adresse liegt im Speicherbereich des Heaps.

coder schrieb:
> ...oder einfach mal d vor dem snprintf irgendwo ausgeben...
d = 1.121999979019165033

Wenn ich d zur Laufzeit (DEbugger)  auf "1.0" setze, ist die Bedingung
1
(fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
 wahr und es wird
1
snprintf(str,64,"%.0f",d);
 mit dem gleichen Fehlercode ausgeführt.
Im Orignalcode von cJSON wird die sprintf-Funktion verwendet. Habe 
snprintf versucht, um einen Überlauf auszuschließen.

von Jo (Gast)


Lesenswert?

Ist... besser gesagt war... doch ein Stack-Problem!
Habe eben den Stack um 512Bytes vergrößert!
Nun geht's! :-D

Dennoch vielen Dank für die Hilfe!

von Eric B. (beric)


Lesenswert?

Jo schrieb:
> Ist... besser gesagt war... doch ein Stack-Problem!
> Habe eben den Stack um 512Bytes vergrößert!
> Nun geht's! :-D

Dann hast du das Problem also nicht behoben, sondern auf später 
verschoben.
Mach erstmal aus dem "%f" ein "%lf", d ist ja ein double...

von Rolf Magnus (Gast)


Lesenswert?

Eric B. schrieb:
> Mach erstmal aus dem "%f" ein "%lf", d ist ja ein double...

%f erwartet einen double. float kann man an printf gar nicht übergeben, 
da das bei der Übergabe automatisch nach double konvertiert wird.

von Eric B. (beric)


Lesenswert?

Rolf Magnus schrieb:
> Eric B. schrieb:
>> Mach erstmal aus dem "%f" ein "%lf", d ist ja ein double...
>
> %f erwartet einen double. float kann man an printf gar nicht übergeben,
> da das bei der Übergabe automatisch nach double konvertiert wird.

Ok, I stand corrected.

Nichtdestotrotz ist "Stack vergrössern" keine wirkliche Lösung. Das 
Problem wird, wenn das Programm ein bisschen wächst, irgendwann mal 
wieder zurückkommen.

von Rolf Magnus (Gast)


Lesenswert?

Eric B. schrieb:
> Nichtdestotrotz ist "Stack vergrössern" keine wirkliche Lösung. Das
> Problem wird, wenn das Programm ein bisschen wächst, irgendwann mal
> wieder zurückkommen.

Was schlägst du denn stattdessen vor, wenn nicht den Stack vergrößeren, 
wenn er zu klein ist?

von Dirk B. (dirkb2)


Lesenswert?

Rolf Magnus schrieb:
> Was schlägst du denn stattdessen vor, wenn nicht den Stack vergrößeren,
> wenn er zu klein ist?

Man kann (große) Arrays via malloc bereitstellen.
Bei structs ab und zu mal ein call by reference statt call by value.

Ich habe nichts gegen das vergrößern vom Stack, nur manchmal ist auch 
dessen Größe auf ein Segment begrenzt.

von karl (Gast)


Lesenswert?

Dirk B. schrieb:
> Man kann (große) Arrays via malloc bereitstellen.

Und das macht es besser? Nein. Alle printf aus der newlib brauchen eh 
Stack und Heap zuhauf. Ich hab Auf ein angepasstes printf umgestellt mit 
eingeschränktem Funktionsumfang.

von Dirk B. (dirkb2)


Lesenswert?

karl schrieb:
> Und das macht es besser?

Ja.

Beim Backport eines Win32-Programms auf DOS hat es wunderbar geklappt.
Auch andere DOS-Programme funktionierten so.

von Karl (Gast)


Lesenswert?

Na dann zeig mal her, wie man den printf(s) der Newlib den Stack 
wegnimmt...

Der TO hat natürlich einige Details unterschlagen, z.B. ob er ein RTOS 
verwendet und einzelne Task-Stacks hat oder ob das alles im main() Stack 
passiert. Bei letzterem ist es auch schon gleich egal, weil Stack und 
Heap oft den selben Platz haben (solange man es nicht geschickter im 
Sinne von robuster löst).

von Rolf M. (rmagnus)


Lesenswert?

Karl schrieb:
> Bei letzterem ist es auch schon gleich egal, weil Stack und
> Heap oft den selben Platz haben (solange man es nicht geschickter im
> Sinne von robuster löst).

Was soll man da großartig robuster machen? Wenn der Prozessor die 
Möglichkeit hat, die Stackgröße zu begrenzen, kann man das natürlich 
tun, aber wie sollte ein Programm sinnvoll reagieren, wenn der Stack 
alle ist?

von W.S. (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Was schlägst du denn stattdessen vor, wenn nicht den Stack vergrößeren,
> wenn er zu klein ist?

Na ganz einfach: etwas anderes als printf und Konsorten verwenden - 
etwas ohne malloc, ohne implizite Konvertierungen nach double und 
anderen Kram, der alles nur aufbläht. Wir sind hier ja nicht auf dem PC, 
sondern im µC. Da sollte man von sowas wie printf besser Abstand nehmen 
und seine paar Ausgaben zu Fuß erledigen.

W.S.

von karl (Gast)


Lesenswert?

Man kann den stack so legen dass er nicht überlaufen kann. Also nicht 
ans Ende des Rams sondern an den Anfang.
Das Programm Stürzt dann sicher ab und man läuft nicht Gefahr, dass was 
komisches passiert wenn zu viel stack belegt wird.

Heap ist in einer eigenen section. _sbrk verteilt nur daraus Speicher.

Viele der linkerskripte im Umlauf machen das anders... der benutzer soll 
ja erstmal nicht behelligt werden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Wir sind hier ja nicht auf dem PC, sondern im µC. Da sollte man von
> sowas wie printf besser Abstand nehmen und seine paar Ausgaben zu Fuß
> erledigen.

Wir sind aber auch nicht mehr auf dem Z8.

Man kann es sich natürlich zur Hauptaufgabe machen, zwei Dutzend
verschiedene Zahlenkonvertierungen zu schreiben, aber man kann auch
die vorhandenen einfach nehmen und in der gewonnenen Zeit dann was
sinnvolles tun.

von W.S. (Gast)


Lesenswert?

Jörg W. schrieb:
> und in der gewonnenen Zeit dann was
> sinnvolles tun.

Bei dem Wetter im Biergarten versacken, ja? Nun, ist auch ne 
Philosophie.

Aber sprintf auf nem µC benutzen zu wollen, ohne den nötigen Durchblick 
zu haben und dann mit nem malloc-Fehler auszusteigen, ist 
vergleichsweise albern. Anschließend das Gejammer hier im Forum: "doesnt 
work, please advise".

Wieder mal die alte Gebetsmühle: Hätte der TO sich an der Lernbetty und 
dem dortigen conv.c ein Beispiel genommen, dann hätte er trotz Verzicht 
auf sprintf genug Zeit für den Biergarten gehabt und so ganz nebenbei 
eine schlanke und versatile Ausgabe seines Krams gehabt, die schlichtweg 
funktioniert.

Aber die Leute sind ja SOOO schlau und wissen alles besser.. bis sie in 
ihrem tatsächlichen Unvermögen auf die Fresse fallen und dann hier 
herumklagen. Doch offensichtlich hilft selbst das AufDieFresseFallen 
nicht, einen Lernprozeß in Gang zu setzen.

Nun denn, bon voyage..

W.S.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
>> und in der gewonnenen Zeit dann was
>> sinnvolles tun.
>
> Bei dem Wetter im Biergarten versacken, ja?

Ich sprach von „was sinnvollem“.

Aber zumindest bist du ja nach reichlich einer Woche Arbeit, die
dich der Verzicht auf sprintf() gekostet hat, wieder aufgetaucht. :-)

von W.S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Ich sprach von „was sinnvollem“.

Ich glaub nicht, daß du das Absacken im Biergarten bei heißem Wetter als 
nicht sinnvoll bezeichnen solltest. Ich zumindest find's OK so.

Aber wenn dich das als Dresdner stört, dann könnten wir ja auch von "im 
Garten von Wackerbarth ein dezentes Schorle genießen" reden. Oder 
meinetwegen auch Vicenz Richter?

W.S.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Aber wenn dich das als Dresdner stört, dann könnten wir ja auch von "im
> Garten von Wackerbarth ein dezentes Schorle genießen" reden.

Zu weit weg, außerdem schon arg dekadent.

Dann lieber Biergarten. :)

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.