Forum: Mikrocontroller und Digitale Elektronik itoa in Verbindung mit Einerstellen im "xx" Format.


von Marius MWH (Gast)


Lesenswert?

...ja, es geht wie so häufig um die Darstellung einer Uhrzeit im Format 
xx:xx, aber leider konvertiert itoa (natürlich) die Einerstellen von zB 
5 Min nicht ins Format "05" - wie macht man das geschickt, gibts da 
vll direkt eine Verwandte von itoa?

Danke, Marius.

von Einer K. (Gast)


Lesenswert?

snprintf() und seine Brüder gefallen dir nicht?

von Marius MWH (Gast)


Lesenswert?

...ne, zu krass. itoa macht mir schon fast zuviel selbst :)

-> Gibts ne lean-e Lsg? Sonst kopiere ich in dem array per hand um 
"if(einstellig)" und adde eine führende 0...aber das ist 
irgendwie...so...hemdsärmelig :)

Marius.

von Teo D. (teoderix)


Lesenswert?

Marius MWH schrieb:
> gibts da
> vll direkt eine Verwandte von itoa?

Mach ne Copy in deinem Projektordner, benenn und Strick sie um!?
(Viel is da ja eh nich dran)

von Bauform B. (bauformb)


Lesenswert?

1
#include <stdio.h>
2
#include <stdlib.h>
3
4
char *
5
ito02a (int value, char *buf)
6
{
7
   int  c1;
8
9
   if (value < 0 || value > 99) {
10
      buf[0] = '?';
11
      buf[1] = '?';
12
   } else {
13
      for (c1 = '0'; c1 <= '9'; c1++) {
14
         if (value < 10) { break; }
15
         value -= 10;
16
      }
17
      buf[0] = c1;
18
      buf[1] = value + '0';
19
   }
20
   buf[2] = '\0';
21
   return buf;
22
}
23
24
int
25
main (int argc, char *argv[])
26
{
27
   char  buf[32];
28
29
   printf ("'%s'\n", ito02a (atoi (argv[1]), buf));
30
   return 0;
31
}

von Marius MWH (Gast)


Lesenswert?

@Teo: Ja, wird vll am besten sein...ich schaue mir das morgen mal an und 
mache eine itoclk draus.

@Bauform: subfcn ito02a -> Ready 2 use?

Marius.

von Stefan F. (Gast)


Lesenswert?

Bauform B. schrieb:
> printf("'%s'\n", ito02a(...))

Soll das ein Aprilscherz sein?

von foobar (Gast)


Lesenswert?

> for (c1 = '0'; c1 <= '9'; c1++)

AI warning: condition c1 <= '9' is always true ;-)


> Soll das ein Aprilscherz sein?

Was passt dir denn daran nicht?

von Stefan F. (Gast)


Lesenswert?

foobar schrieb:
>> Soll das ein Aprilscherz sein?
> Was passt dir denn daran nicht?

Printf kann bereits Zahlen zweistellig formatieren. Die alternative 
Methode macht nur Sinn, wenn man zugleich auf printf verzichtet.

von foobar (Gast)


Lesenswert?

Das ist doch nur Test-/Beispielkode, um zu zeigen, was die Funktion 
macht.

von Rolf M. (rmagnus)


Lesenswert?

foobar schrieb:
>> for (c1 = '0'; c1 <= '9'; c1++)
>
> AI warning: condition c1 <= '9' is always true ;-)

Vielleicht so?
1
c1 = '0';
2
while (value >= 10)
3
{
4
    c1++;
5
    value -= 10;
6
}

Stefan ⛄ F. schrieb:
> Printf kann bereits Zahlen zweistellig formatieren. Die alternative
> Methode macht nur Sinn, wenn man zugleich auf printf verzichtet.

Das printf ist hier ganz offensichtlich nur Teil des Beispielcodes, 
damit man ein vollständiges Programm hat, das man mal laufen lassen 
kann. Es dient nur dazu, die Funktion ito02a mal in Aktion sehen zu 
können. Der TE hat ja ausdrücklich geschrieben, dass er kein *printf() 
nutzen will.

: Bearbeitet durch User
von foobar (Gast)


Lesenswert?

> Vielleicht so?

zum Beispiel, ja.  Aber höchstwahrscheinlich benutzt er eh irgendwo 
Divisionen, dann wäre
1
    buf[0] = '0' + value / 10;
2
    buf[1] = '0' + value % 10;
zwar nicht schneller aber eleganter und kürzer.

von Bauform B. (bauformb)


Lesenswert?

foobar schrieb:
> höchstwahrscheinlich benutzt er eh irgendwo
> Divisionen, dann wäre    buf[0] = '0' + value / 10;
>     buf[1] = '0' + value % 10;
> zwar nicht schneller aber eleganter und kürzer.

Eleganz liegt im Auge des Betrachters. In dieser speziellen Anwendung 
wäre eine Division Overkill, weil nämlich:

Marius MWH schrieb:
> ...ne, zu krass. itoa macht mir schon fast zuviel selbst :)

Außerdem: sind das nicht sogar zwei Divisionen? Oder schafft es der 
Compiler tatsächlich, den Rest aus der ersten Division zu nutzen?

von foobar (Gast)


Lesenswert?

> sind das nicht sogar zwei Divisionen? Oder schafft es der
> Compiler tatsächlich, den Rest aus der ersten Division zu nutzen?

Aus
1
    buf[0] = '0' + value / 10;
2
    buf[1] = '0' + value % 10;
wird
1
    ldi r22,lo8(10)
2
    call __udivmodqi4
3
    subi r24,lo8(-(48))
4
    st Z,r24
5
    subi r25,lo8(-(48))
6
    std Z+1,r25

von Rolf M. (rmagnus)


Lesenswert?

Bauform B. schrieb:
> Außerdem: sind das nicht sogar zwei Divisionen? Oder schafft es der
> Compiler tatsächlich, den Rest aus der ersten Division zu nutzen?

Falls der Compiler es nicht schaffen sollte, könnte man schauen, ob er 
die Standard-Funktion div() unterstützt. Die gibt Ergebnis und Rest 
zurück.

von Stefan F. (Gast)


Lesenswert?

Bauform B. schrieb:
> Außerdem: sind das nicht sogar zwei Divisionen? Oder schafft es der
> Compiler tatsächlich, den Rest aus der ersten Division zu nutzen?

Das ist eine gute Frage auf die ich auch schon einmal gestossen bin. Wie 
kann ich ohne großartige Klimzüge das Ergebnis einer Division und den 
Rest in einem Abwasch bekommen? Das scheint zumindest im C Quelltext 
nicht möglich zu sein.


foobar schrieb:
>> sind das nicht sogar zwei Divisionen? Oder schafft es der
>> Compiler tatsächlich, den Rest aus der ersten Division zu nutzen?
>
> Aus
>     buf[0] = '0' + value / 10;
>     buf[1] = '0' + value % 10;
> wird
>     ldi r22,lo8(10)
>     call __udivmodqi4
>     subi r24,lo8(-(48))
>     st Z,r24
>     subi r25,lo8(-(48))
>     std Z+1,r25

Sehr interessant. Ich hätte nicht gedacht, dass der Compiler so "schlau" 
ist.

von foobar (Gast)


Lesenswert?

> Wie kann ich ohne großartige Klimzüge das Ergebnis einer Division und
> den Rest in einem Abwasch bekommen?

Wie oben gezeigt, einfach ausschreiben.  Das kommt so häufig vor, dass 
der GCC das schon in der 1er-Version optimieren konnte ;-)

von Rolf M. (rmagnus)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das scheint zumindest im C Quelltext nicht möglich zu sein.

Wie gesagt:

Rolf M. schrieb:
> die Standard-Funktion div()

http://www.cplusplus.com/reference/cstdlib/div/

von W.S. (Gast)


Lesenswert?

Marius MWH schrieb:
> ...ne, zu krass. itoa macht mir schon fast zuviel selbst :)
>
> -> Gibts ne lean-e Lsg? Sonst kopiere ich in dem array per hand um
> "if(einstellig)" und adde eine führende 0...aber das ist
> irgendwie...so...hemdsärmelig :)


Tja, immer wieder stolpern die Leute über Kleinigkeiten, die bereits 
seit Jahren gelöst sind und als fertige benutzbare Lösungen vorliegen. 
Aber man ist ja über die einfachen und kleinen Lösungen erhaben...

Das ist ne Universalroutine, die man auch ganz leicht auf int64 
erweitern kann (falls das gebraucht wird) - aber für den vorliegenden 
Fall kann man sie auch drastisch zusammenkürzen, weil die Uhrzeit ja 
wohl nicht als long vorliegen muß und auch nicht negativ werden kann...
1
/******************************************************************************
2
   Dezimal-Konvertierung Long in Pufferbereich.
3
   digits = gewünschte Anzahl Stellen.
4
            digits<0 = mit führenden Nullen,
5
      sonst    = mit führenden Leerzeichen
6
   Buffer = Zeiger auf den Ergebnispuffer, mindestens 4 Byte groß.
7
   BufLen = Gesamtgröße des Ergebnispuffers. Soll mindestens 3 Byte größer
8
            sein als digits
9
 ******************************************************************************/
10
11
long LONGtoStr (long aValue, int digits, char* Buffer, int BufLen)
12
{ char* P;
13
  char* Q;
14
  long  L;
15
  char  v;
16
  int   i, j, k;
17
  ldiv_t T;
18
19
  *Buffer = 0;
20
  if (BufLen<4) return aValue;
21
22
  i = BufLen - 1;
23
  j = digits;
24
  if (j<0) j = -j;
25
26
  if (i < (j+3))      /* mehr Stellen als Bufferplatz */
27
  { Buffer[0] = '?';
28
    Buffer[1] = 0;
29
    return aValue;
30
  }
31
32
  Buffer[i--] = 0;    /* Endemarker setzen */
33
  if (aValue<0)
34
       { L = -aValue;
35
         v = 1;
36
       }
37
  else { L = aValue;
38
         v = 0;
39
       }
40
41
  if (!L)  Buffer[i--] = '0';
42
  while (i)
43
  { if (!L) goto _lready;
44
    T = ldiv(L,10);
45
    L = T.quot;
46
    Buffer[i--] = '0'+T.rem;
47
  }
48
49
                     /* i = 0, d.h. der Buffer ist voll! */
50
  i = 0; j = BufLen - 2;
51
  Buffer[i++] = '>';
52
  while (i<j) Buffer[i++] = '9';
53
  return aValue;
54
55
56
/* So, die Ziffern sind erzeugt, jetzt wird formatiert.
57
   i zeigt auf freien Platz vor 1. Ziffer
58
 */
59
60
_lready:
61
  k = BufLen - i - 2;       /* k = Anzahl gehabter Digits */
62
63
  if (digits < 0)           /* mit Nullen auffüllen */
64
  { j = -digits;            /* j = Sollstellenzahl */
65
    if (v) k++;             /* eine Stelle für '-' berücksichtigen */
66
    while (k++ < j)
67
    { if (i > 0) Buffer[i--] = '0'; }
68
69
    if (v) Buffer[i--]= '-'; /* Vorzeichen eintragen */
70
  }
71
72
  else                      /* mit Spaces auffüllen */
73
  { if (v)
74
     { Buffer[i--] = '-';   /* Vorzeichen eintragen */
75
       k++;                 /* Stelle berücksichtigen */
76
     }
77
     j = digits;
78
     while (k++ < j)
79
     { if (i > 0) Buffer[i--] = ' '; }
80
  }
81
  ++i;                 /* i zeigt jetzt auf 1. Zeichen */
82
  if (i)
83
  { P = Buffer;
84
    Q = &Buffer[i];
85
    j = BufLen - 1;
86
    while (j--) *P++ = *Q++;
87
    *P = 0;
88
  }
89
  return aValue;
90
}

W.S.

von Marius MWH (Gast)


Lesenswert?

...ehm, ich geb zu, ich habe keinen Plan (mehr):

Wo finde ich itoa.c in WINAVR? Ich suche mit der Suche, finde aber nur 
die .h?

Danke, Marius.

von Einer K. (Gast)


Lesenswert?

Marius MWH schrieb:
> ...ehm, ich geb zu, ich habe keinen Plan (mehr):
>
> Wo finde ich itoa.c in WINAVR? Ich suche mit der Suche, finde aber nur
> die .h?
>
> Danke, Marius.

Steckt sicherlich vorkompiliert in einer *.a

Musst also in die LibC Quellen schauen.
z.B.
https://github.com/vancegroup-mirrors/avr-libc/blob/06cc6ff5e6120b36f1b246871728addee58d3f87/avr-libc/libc/stdlib/atoi.S

von Marius MWH (Gast)


Lesenswert?

Hallo zusammen,

@Bauform: Klappt wunderbar - Danke!

Was mich wurm - ich schreibe die Zeit - und momentan testweise NUR diese 
- auf das LCD. Aber da fehlen manchmal ganze Werte (buffer) oder diese 
sind leer...iwie willkürlich.

Ist es böse, z.B. folgendes * zu tun (nein, das ist kein code sondern 
nur der relevante ablauf)?
1
char char clock_min=55, LCD_clock_min[2];
2
3
itoclk(clock_min, LCD_clock_min);
4
5
LCD_print(1,2, LCD_clock_hour);
6
LCD_print(1,4, ":");
7
LCD_print(2,5, LCD_clock_min);
8
LCD_print(2,7," - ");
9
LCD_print(3,10, LCD_clock_day);
10
11
void LCD_print (char LCD_row, char LCD_column, char LCD_txt[12]) {
12
13
...
14
15
}

-> Vll ist die übergabe eines buffers an einen buffer gefährlich?

Marius.

von MaWin (Gast)


Lesenswert?

W.S. schrieb:
> fertige benutzbare Lösungen

Für eine 2-stellige Zahl ?

Derselbe Irrsinn, der heute zu megabytegrossen Programmen führt die nur 
Kinderkacke ausrechnen  (Und dann kann es nichtmal int64).

von W.S. (Gast)


Lesenswert?

MaWin schrieb:
> Für eine 2-stellige Zahl ?

Habe ich nicht ausdrücklich geschrieben, daß man sie für den 
vorliegenden Fall DRASTISCH zusammenkürzen kann?

Ja, natürlich habe ich das. Du konntest das offenbar nicht lesen.

Abgesehen davon erwarte ich von einem C-Programmierer, daß er div und 
ldiv kennt und anzuwenden weiß. Warum wird dann in diesem Thread von 
itoa und Puffer-Akrobatik gefaselt?

Abgesehen davon ist die gezeigte Routine in übersetzter Form 
ausgesprochen klein im Vergleich zu sowas wie printf und Konsorten. 
Genau DAS führt nämlich zu schlanken Programmen - im Gegensatz zu 
deiner Annahme.

W.S.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

MaWin schrieb:
> W.S. schrieb:
>> fertige benutzbare Lösungen
>
> Für eine 2-stellige Zahl ?
>
> Derselbe Irrsinn, der heute zu megabytegrossen Programmen führt die nur
> Kinderkacke ausrechnen  (Und dann kann es nichtmal int64).

Und dann noch Spaghetticode mit goto hingerotzt.
Der Herr programmiert wie ne eins!

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

W.S. schrieb:
> Abgesehen davon ist die gezeigte Routine in übersetzter Form
> ausgesprochen klein im Vergleich zu sowas wie printf und Konsorten.
> Genau DAS führt nämlich zu schlanken Programmen - im Gegensatz zu
> deiner Annahme.

Willst du dir schonwieder ne blutge Nase holen?
Es wurde dir schon zig mal erklärt wie man printf klein bekommt.

von Marius MWH (Gast)


Lesenswert?

...ehm, könnt ihr mir vll kurz bei meinem Buffer->Buffer Problem helfen? 
:)

Testweise LCD_print(1,2, "12"); schreibt sauber in Zeile 1, Pos 2 eine 
"12". Das geht aber halt nicht mit dem Buffer...

Marius.

von foobar (Gast)


Lesenswert?

> könnt ihr mir vll kurz bei meinem Buffer->Buffer Problem helfen?

> char char clock_min=55, LCD_clock_min[2];

"char char" gibts nicht, ein "char" reicht.  Weiter: LCD_clock_min muß 3 
Elemente fassen können, die 2 Ziffern und das terminierende \0.

> void LCD_print (char LCD_row, char LCD_column, char LCD_txt[12])

Zwar nicht falsch, aber verbesserungswürdig: Bei row und column wäre ein 
(definiter) unsigned Typ angemessener, z.B. uint8_t.  LCD_txt wird 
üblicherweise als "char *LCD_txt" definiert (dazu degeneriert das 
nämlich) - alles andere führt nur in die Irre.

von MaWin (Gast)


Lesenswert?

W.S. schrieb:
> Abgesehen davon erwarte ich von einem C-Programmierer, daß er div und
> ldiv kennt und anzuwenden weiß. Warum wird dann in diesem Thread von
> itoa und Puffer-Akrobatik gefaselt

Eigentlich nicht mehr, seit

foobar schrieb:
> dann wäre
>     buf[0] = '0' + value / 10;
>     buf[1] = '0' + value % 10;
>

sollte das Problem durch sein.

von foobar (Gast)


Lesenswert?

W.S. schrieb:
> Tja, immer wieder stolpern die Leute über Kleinigkeiten, die bereits
> seit Jahren gelöst sind

Tja, du leider auch:
1
>  long L;
2
>  ...
3
>  if (aValue<0)
4
>       { L = -aValue;
5
>         v = 1;
6
>       }
Probier deine Routine mal mit -2147483648 aus.


Btw, ist das Absicht, dass die Routine so ziemlich gegen jede 
Konvention verstößt?

von Marius MWH (Gast)


Lesenswert?

foobar schrieb:
>> könnt ihr mir vll kurz bei meinem Buffer->Buffer Problem helfen?
>
>> char char clock_min=55, LCD_clock_min[2];
>
> "char char" gibts nicht, ein "char" reicht.

-> Sry, Tippefehler - ist natürlich nur ein char :)

>Weiter: LCD_clock_min muß 3
> Elemente fassen können, die 2 Ziffern und das terminierende \0.

-> OK, die Darstellung wir auch besser wenn ich buf[2]="\0" 
auskommentiere...aber es fehlen immer noch Inhalte *

>
>> void LCD_print (char LCD_row, char LCD_column, char LCD_txt[12])
>
> Zwar nicht falsch, aber verbesserungswürdig: Bei row und column wäre ein
> (definiter) unsigned Typ angemessener, z.B. uint8_t.  LCD_txt wird
> üblicherweise als "char *LCD_txt" definiert (dazu degeneriert das
> nämlich) - alles andere führt nur in die Irre.

-> Hm, da hört mein Verständnis leider auf...

* -> Ich poste gleich mal ein Bild des LCDs, damit man versteht, was ich 
meine...

Marius.

von Marius MWH (Gast)


Lesenswert?

...ich flipp aus - wenn ich ALLE buf von [2] auf [3] ändere, gehts, 
einwandfreie Darstellung! Ich hatte gestern immer nur minute ODER std 
von [2] auf [3] geändert, aber dann wird itoclk das "\0" einfach über 
den nächsten geschrieben haben und dann war dort "blanko"...oder sowas. 
Also kein sauberes buf-Mgmt :)

Danke vielmals für den Wink, foobar!!!

Marius.

von foobar (Gast)


Lesenswert?

> ... wenn ich ALLE buf von [2] auf [3] ändere, gehts, ...

Deshalb macht man das einmal richtig und kann es danach vergessen:
1
#include <stdio.h>
2
#include <stdint.h>
3
#include <stdarg.h>
4
...
5
void LCD_printf(uint8_t row, uint8_t col, char *fmt, ...)
6
{
7
    char buf[16]; // enough for one LCD line
8
    va_list va;
9
10
    va_start(va, fmt);
11
    vsnprintf(buf, sizeof(buf), fmt, va);
12
    va_end(va);
13
14
    LCD_print(row, col, buf);
15
}
16
...
17
    LCD_printf(1, 1, "%02u:%02u:%02u", hours, minutes, seconds);
18
    LCD_printf(2, 1, "%04u-%02u-%02u", year, month, day);
19
...

von Einer K. (Gast)


Lesenswert?

foobar schrieb:
> Deshalb macht man das einmal richtig und kann es danach vergessen:

printf und seine Brüder sind in diesem Thread explizit unerwünscht!

von foobar (Gast)


Lesenswert?

> printf und seine Brüder sind in diesem Thread explizit unerwünscht!

Na ja, Anfänger sind evtl ja noch nicht so beratungsresistent ;-)

von W.S. (Gast)


Lesenswert?

MaWin schrieb:
> Eigentlich nicht mehr, seit..

Man müßte das bloß den übrigen Disputanden mal klarmachen.


Eigentlich ist das sowas von trivial, daß mich dieser gesamte Thread im 
Grunde graust.

Trotz der inzwischen wirklich sinnreichsten Lösung (ein paarmal div() 
und der String ist final fertig) wird hier immer noch mit obskuren 
Puffer-Basteleien gearbeitet - mit eigentümlichem Ergebnis wie man 
sieht:

Marius MWH schrieb:
> ...ich flipp aus

nana, lieber nicht. Stattdessen einfach den String selber aufsetzen. Wie 
wurde dir ja schon gezeigt.

W.S.

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.