Forum: Compiler & IDEs itoa in Großbuchstaben ausgeben


von Lokus P. (derschatten)


Lesenswert?

Ich möchte gerne einen HEX-Wert auf einem LCD in Großbuchstaben 
ausgeben.

Jetzt hab ich schon folgendes Versucht:
1
lcd_puts(itoa(toupper(irmp_data.address),s,16));

Allerdings funkt das nicht.

Geht das so überhaupt?

: Verschoben durch Admin
von Max H. (hartl192)


Lesenswert?

Lokus Pokus schrieb:
> Geht das so überhaupt?
Nein, so würde es gehen:
1
  char *p_str = itoa(toupper(irmp_data.address),s,16);
2
  while(*p_str)
3
  {
4
    *p_str = toupper(*p_str);
5
    p_str++;
6
  }
7
  lcd_puts(s);

von Oliver J. (skriptkiddy)


Lesenswert?

Versuchs mal mit toupper(...)

von Max H. (hartl192)


Lesenswert?

Sry, blöder Fehler, der Code sollte so aussehen:
1
  char *p_str = itoa(irmp_data.address, s, 16);
2
  while(*p_str)
3
  {
4
    *p_str = toupper(*p_str);
5
    p_str++;
6
  }
7
  lcd_puts(s);

: Bearbeitet durch User
von Irgendwer (Gast)


Lesenswert?

1
itoa(irmp_data.address,s,16);
2
strupr(s);
3
lcd_puts(s);

oder

wenn man nicht mit jeden Byte geizen muss und das ganze eventuell auch 
etwas weitergehend Formatieren will.
1
snprintf(s,sizeof(s)-1,"%X",irmp_data.address);
2
lcd_puts(s);

von Lokus P. (derschatten)


Lesenswert?

Danke euch.

jetzt würde ich der Ausgabe gerne noch führende Nullen voran setzen.

Also eigentlich immer auf 5 Zeichen auffüllen.

von grundschüler (Gast)


Lesenswert?

1
  void  lcd_hex16(uint16_t byteX)
2
  //
3
  {
4
 //byteX =65000;
5
  uint8_t x;
6
char dummy[6]={'x','0','0','0','0','\0'};
7
  x=byteX/4096;
8
     if(x<10){
9
    dummy[1]=(x+48);
10
    }else{
11
    dummy[1]=(x+55);
12
    }
13
  x=(byteX%4096)/256;
14
     if(x<10){
15
    dummy[2]=(x+48);
16
    }else{
17
    dummy[2]=(x+55);
18
    }
19
    
20
   x=(byteX%256)/16;
21
    if(x<10){
22
    dummy[3]=(x+48);
23
    }else{
24
    dummy[3]=(x+55);
25
    }
26
   x=(byteX%16);
27
    
28
     if(x<10){
29
    dummy[4]=(x+48);
30
    }else{
31
    dummy[4]=(x+55);
32
    }
33
  std_lcd_print_string_to_cursor_position(dummy);  
34
    
35
  }

von Lokus P. (derschatten)


Lesenswert?

geht das nicht etwas kompakter?
Oder ist das so aufwändig weil ich hier mit HEX-Weerten arbeite?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Auf 5 Stellen füllen mit führenden Nullen:

   snprintf(s,sizeof(s)-1,"%05X",irmp_data.address);
   lcd_puts(s);

Einfacher gehts nicht.

Aber warum auf 5 Stellen? Der maximale Wert, den Du von IRMP bekommst, 
ist 4 stellig, nämlich 0xFFFF.

Also:

  snprintf(s,sizeof(s)-1,"%04X",irmp_data.address);
  lcd_puts(s);

Um anzudeuten, dass es sich um eine Hex-Zahl handelt:

  snprintf(s,sizeof(s)-1,"0x%04X",irmp_data.address);

Verbrät allerdings 6 Stellen auf Deinem Display. Achte darauf, das Array 
s[] groß genug zu wählen, also mindestens:

  char s[7];   // 6 Stellen + '\0'

: Bearbeitet durch Moderator
von npn (Gast)


Lesenswert?

Oliver Ju. schrieb:
> Versuchs mal mit toupper(...)

Lokus Pokus schrieb:
> Jetzt hab ich schon folgendes Versucht:
> lcd_puts(itoa(toupper(irmp_data.address),s,16));
                ^--- hat er doch!
Nur der Rest war nicht richtig, siehe andere Beiträge...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
>   snprintf(s,sizeof(s)-1,"%04X",irmp_data.address);

Ich habe gerade mal ins Manual von snprintf() geschaut:

"The functions snprintf() and vsnprintf() write at most size bytes 
(including the terminating null byte ('\0')) to str."

Korrekt wäre demnach:

  snprintf (s, sizeof(s), "%04X", irmp_data.address);

Sonst könnte am Ende eine Stelle fehlen, wenn man das Array s[] von der 
Größe her genau passend macht.

von grundschüler (Gast)


Lesenswert?

Lokus Pokus schrieb:
> geht das nicht etwas kompakter?

klar, mit Schleife. Die Funktion steht genau einmal in der 
lcd-standard-lib und wird dann nie mehr angefasst. Sie geht - weil sie 
einfach ist - immer und überall uc-übergreifend mit ARM und AVR-IDEs.

Du kannst es aber auch mit Schleife oder itoa oder snprintf machen. Ist 
dann aber - wie die Beiträge zeigen - nicht mehr ganz so einfach.

von Udo S. (urschmitt)


Lesenswert?

Lokus Pokus schrieb:
> Jetzt hab ich schon folgendes Versucht:
> lcd_puts(itoa(toupper(irmp_data.address),s,16));
>
> Allerdings funkt das nicht.

Wäre eine schöne Übung um deine C Kenntnisse zu verbessern zu erkennen 
WARUM das so nicht funkt.
Kleiner Tipp: Was ist der Variablentyp der Eingangsvariable von itoa() 
und was ist der Ein und Ausgangstyp von toupper().

von Irgendwer (Gast)


Lesenswert?

Frank M. schrieb:
> Sonst könnte am Ende eine Stelle fehlen, wenn man das Array s[] von der
> Größe her genau passend macht.

Und was passiert wenn du eine String bis aufs letzte Zeichen voll 
quetschst?
Das abschließende Nullbyte fehlt und deine nachfolgende Funktion gibt 
solange Zeichen aus irgendwo im Speicher aus Zufall mal eine null kommt.
Genaugenommen müsste noch eine s[sizeof(s)-1]=0; einfügt werden.
Bei meiner Variante langt es aber wenn du das einmalig in der nähe der 
Deklaration von s machst (außer wenn "s" diese eh komplett mit Null 
initialisiert wird) weil diese null nie überschrieben wird.
Bei deiner Variante müsstest du das nach jedem snprintf machen!

von Schaulus Tiger (Gast)


Lesenswert?

Irgendwer schrieb:
> Frank M. schrieb:
>> Sonst könnte am Ende eine Stelle fehlen, wenn man das Array s[] von der
>> Größe her genau passend macht.
>
> Und was passiert wenn du eine String bis aufs letzte Zeichen voll
> quetschst?
> Das abschließende Nullbyte fehlt und deine nachfolgende Funktion gibt
> solange Zeichen aus irgendwo im Speicher aus Zufall mal eine null kommt.

Kann es sein, dass dein snprintf() kaputt ist? Meins macht es so:
1
#include <stdio.h>
2
3
void
4
zweifel (int zahl)
5
{
6
char  array[8];
7
int   i;
8
9
  snprintf (array, sizeof(array), "%d", zahl);
10
  printf ("%10d -> ", zahl);
11
  for (i = 0; i < 8; i++) {
12
    printf (" %d", array[i]);
13
  }
14
  puts ("");
15
  return;
16
}
17
18
int
19
main (void)
20
{
21
  zweifel (12345);
22
  zweifel (123456);
23
  zweifel (1234567);
24
  zweifel (12345678);
25
  zweifel (123456789);
26
  zweifel (12345678);
27
  zweifel (1234567);
28
  zweifel (123456);
29
  zweifel (12345);
30
  return 0;
31
}
1
     12345 ->  49 50 51 52 53 0 4 8
2
    123456 ->  49 50 51 52 53 54 0 8
3
   1234567 ->  49 50 51 52 53 54 55 0
4
  12345678 ->  49 50 51 52 53 54 55 0
5
 123456789 ->  49 50 51 52 53 54 55 0
6
  12345678 ->  49 50 51 52 53 54 55 0
7
   1234567 ->  49 50 51 52 53 54 55 0
8
    123456 ->  49 50 51 52 53 54 0 0


Den ganzen Stress und ein paar Byte RAM kann man sich sparen, wenn man 
sich ein lcd_printf() schreibt, das die Zeichen direkt ausgibt, ohne 
Umweg über einen Zwischenpuffer.

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


Lesenswert?

Schaulus Tiger schrieb:
> wenn man sich ein lcd_printf() schreibt, das die Zeichen direkt ausgibt

Oder ein lcd_putchar(), und dann fprintf() nehmen.

Habe mir letztens einen Mini-VT100-Emulator dafür geschrieben, dann
kann man auch Cursorpositionierung und Löschen gleich noch eingebettet
im Zeichenstrom erledigen.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Irgendwer schrieb:
> Und was passiert wenn du eine String bis aufs letzte Zeichen voll
> quetschst?
> Das abschließende Nullbyte fehlt und deine nachfolgende Funktion gibt
> solange Zeichen aus irgendwo im Speicher aus Zufall mal eine null kommt.

Unsinn. Kannst Du nicht lesen? Hier nochmal das Zitat aus dem Manual:

"The functions snprintf() and vsnprintf() write at most size bytes
(including the terminating null byte ('\0')) to str."

Das heisst:

  1. Es werden höchstens size Zeichen geschrieben
  2. Das letzte Zeichen ist immer '\0'

Ergo: Der String wird immer terminiert.

> Genaugenommen müsste noch eine s[sizeof(s)-1]=0; einfügt werden.

Doppel-Falsch:

 a) sizeof(s)-1 ist falsch: Du hast ein Zeichen zu wenig, weil
    snprintf() bereits mit '\0' terminiert - und zwar bereits
    an der Stelle sizeof(s)-2, wenn Du sizeof(s)-1 als Argument
    heruntergibst.

 b) Eigene Terminierung ist doppelt gemoppelt.

> Bei deiner Variante müsstest du das nach jedem snprintf machen!

Unsinn.

Du hast snprintf() nicht verstanden. Ich habe meine Korrektur doch genau 
mit dem Manual-Auszug begründet. Wie konnte Dir das entgehen?

Wahrscheinlich bist Du einer der Übervorsichtigen: Array vorsichtshalber 
128 Bytes groß, obwohl nur 16 Stellen benutzt werden. Da fällt Dir 
natürlich eine vorzeitige Terminierung von snprintf() an der Stelle 
sizeof(s)-2 gar nicht auf ;-)

P.S.
Du verwechselst das Verhalten offenbar mit strncpy(). Da hättest Du 
nämlich Recht, strcnpy() ist tatsächlich ziemlich fies in dieser 
Hinsicht. Es knallt den Target-String bis zur Stelle n-1 (inkl.) voll 
und terminiert dann tatsächlich nicht, wenn kein Platz mehr ist.

: Bearbeitet durch Moderator
von Lokus P. (derschatten)


Lesenswert?

welche Variante ist nun die richtige?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Schrieb ich doch oben:
1
  char s[5];
2
  snprintf (s, sizeof(s), "%04X", irmp_data.address);
3
  lcd_puts(s);

von Lokus P. (derschatten)


Lesenswert?

die Großschreibung ist da jetzt aber nicht inkludiert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lokus Pokus schrieb:
> die Großschreibung ist da jetzt aber nicht inkludiert.

Klar: %x macht klein, %X macht groß. %04X füllt mit Nullen auf, bis das 
Ding insgesamt 4 Stellen hat.

Ist also eine Rundum-Lösung für Dich.

: Bearbeitet durch Moderator
von grundschüler (Gast)


Lesenswert?

Lokus Pokus schrieb:
> welche Variante ist nun die richtige?


Das entscheidest du. Leistungsvergleich:
1
void  lcd_hex16(uint16_t byteX){
2
#if 0
3
//Variante A:
4
uint8_t x,i;
5
char dummy[6]={'x','0','0','0','0','\0'};
6
7
for(i=0;i<5;i++){
8
  x=(byteX%(65536>>(4*i)))/(4096>>(4*i));
9
     if(x<10){
10
    dummy[i+1]=(x+48);
11
    }else{
12
    dummy[i+1]=(x+55);
13
    }
14
}
15
#else
16
//Variante B:
17
 char dummy[5];
18
  snprintf (dummy, sizeof(dummy), "%04X", 1000);
19
20
#endif
21
    
22
std_lcd_print_string_to_cursor_position(dummy);  
23
}


Variante A: 7792 Bytes
Variante B: 9096 Bytes
A erfüllt alle Anforderungen, ist einfacher und kürzer...

von Karl H. (kbuchegg)


Lesenswert?

grundschüler schrieb:

Solange du sowas schreibst
>   x=(byteX%(65536>>(4*i)))/(4096>>(4*i));
sollte man den Leistungsvergleich erst mal links liegen lassen.

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


Lesenswert?

grundschüler schrieb:
> ist einfacher

hüstel, hüstel …

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

grundschüler schrieb:
>   x=(byteX%(65536>>(4*i)))/(4096>>(4*i));

Sag mal, weisst Du, was Du da tust?

65536 ist schon kein uint16_t mehr, da ist nämlich bei 65535 Schluss. Du 
shiftest also einen Long (falls der Compiler 65636 ohne "L" dahinter 
überhaupt versteht) um einen variablen Wert.

Da eine ATmega keinen Barrel-Shifter hat, kommt da eine gaaaaanz lange 
Schleife raus.

Das Ganze 2 mal. Das ist krass.

Variante A: 7792 Bytes

Das mach ich mit weniger als einem Zehntel.

> A erfüllt alle Anforderungen, ist einfacher und kürzer...

Von einfacher kann keine Rede sein.

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
> falls der Compiler 65636 ohne "L" dahinter überhaupt versteht

Ja, macht er, muss er machen.

Aber das Ding taugt eher als Einstieg in den IOCCC denn als eine
allgemein anpreisbare Implementierung.

Dass ein printf nicht klein ist, ist von vornherein klar.  Aber
sofern man die paar Bytes mehr nicht gerade wirklich knausern muss,
weil man den falschen Controller für den Job gewählt hat (oder das
Pflichtenheft auf mysteriöse Weise sich mittlerweile verdoppelt hat ;),
dann hat man mit der printf-Familie auf jeden Fall eine Lösung, bei
der man ohne graue Haare schnell zum Ziel kommt, weil man sich auf
das Wesentliche konzentrieren kann, statt sich mit derartigen
Nebensächlichkeiten abquälen zu müssen.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Ja, macht er, muss er machen.

Ich erinnere mich noch an Zeiten, da musste man für F_CPU bei 8000000 
immer ein L dranpappen, damit es richtig übersetzt wurde ;-)

> Aber das Ding taugt eher als Einstieg in den IOCCC denn als eine
> allgemein anpreisbare Implementierung.

grundschüler hat etwas ähnliches kryptisches in "Projekte und Code" 
gepostet. Ein Source, den weder ein Mensch noch ein Compiler verstehen 
kann. Das grenzt schon an Unverschämtheit.

> Dass ein printf nicht klein ist, ist von vornherein klar.  Aber
> sofern man die paar Bytes mehr nicht gerade wirklich knausern muss,
> weil man den falschen Controller für den Job gewählt hat (oder das
> Pflichtenheft auf mysteriöse Weise sich mittlerweile verdoppelt hat ;),
> dann hat man mit der printf-Familie auf jeden Fall eine Lösung, bei
> der man ohne graue Haare schnell zum Ziel kommt, weil man sich auf
> das Wesentliche konzentrieren kann, statt sich mit derartigen
> Nebensächlichkeiten abquälen zu müssen.

Das sehe ich genauso. Gefragt war eine einfache Lösung. snprintf() 
ist eine einfache Lösung.

Wenn man die kürzeste Lösung haben will:
1
#include <stdint.h>
2
3
static uint8_t
4
itox (uint8_t val)
5
{
6
    uint8_t rtc;
7
8
    val &= 0x0F;
9
10
    if (val <= 9)
11
    {
12
        rtc = val + '0';
13
    }
14
    else
15
    {
16
        rtc = val - 10 + 'A';
17
    }
18
    return (rtc);
19
}
20
21
static void
22
itoxx (char * xx, unsigned char i)
23
{
24
    *xx++ = itox (i >> 4);
25
    *xx++ = itox (i & 0x0F);
26
}
27
28
static void
29
itoxxxx (char * xx, unsigned int i)
30
{
31
    itoxx (xx, i >> 8);
32
    itoxx (xx + 2, i & 0x0FF);
33
}
34
35
int
36
main ()
37
{
38
   char buf[5];
39
40
   uint16_t u = 1234;
41
42
   itoxxxx (buf, u);
43
   buf[4] = '\0';
44
}

Verbraucht gerade mal 224 Bytes im Flash, also weitab von der 
verkorksten Lösung von grundschüler. Ausserdem bietet es 1, 2 und 4 
stellige Ausgabe an :-)

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


Lesenswert?

Frank M. schrieb:
> Ich erinnere mich noch an Zeiten, da musste man für F_CPU bei 8000000
> immer ein L dranpappen, damit es richtig übersetzt wurde ;-)

Nö, machen die Leute nur aus Gewohnheit.

Für <util/delay.h> kann man auch 8E6 schreiben, dann spart man sich
das mühselige Zählen der Nullen. ;-)  <util/setbaud.h> braucht es aber
als Ganzzahl.

von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch schrieb:
> Frank M. schrieb:
>> Ich erinnere mich noch an Zeiten, da musste man für F_CPU bei 8000000
>> immer ein L dranpappen, damit es richtig übersetzt wurde ;-)
>
> Nö, machen die Leute nur aus Gewohnheit.
>


War da nicht irgendwas mit dem unsigned. Denn eigentlich lautet es ja
1
#define F_CPU 8000000UL
und das U für unsigned war wichtig. Ich kann aber nicht mehr sagen, bei 
welcher Berechnung da dann was schief ging. Könnte irgendwas mit 
Bitshifts zb bei Baudratenberechnung zu tun haben. Aber genaueres weiss 
ich auch nicht mehr.

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


Lesenswert?

Karl Heinz schrieb:
> War da nicht irgendwas mit dem unsigned.

Ja, das eher noch.  Kann sein, dass sonst ein Zwischenergebnis
mal negativ wird.  Hängt aber natürlich davon ab, was man mit F_CPU
noch so anstellt.  <util/delay.h> benutzt den Makro sowieso innerhalb
von Gleitkommaberechnungen, da ist das egal.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> War da nicht irgendwas mit dem unsigned. Denn eigentlich lautet es ja
>
1
> #define F_CPU 8000000UL
2
>
> und das U für unsigned war wichtig.

Ja, kann tatsächlich so gewesen sein. Ich habs auch nicht mehr so genau 
im Kopf. Aber irgendwas war da mal. Ist aber schon ein paar Jährchen 
her.

Egal.

von Lokus P. (derschatten)


Lesenswert?

> int
> main ()
> {
>    char buf[5];
>
>    uint16_t u = 1234;
>
>    itoxxxx (buf, u);
>    buf[4] = '\0';
> }
> [/c]
>
> Verbraucht gerade mal 224 Bytes im Flash, also weitab von der
> verkorksten Lösung von grundschüler. Ausserdem bietet es 1, 2 und 4
> stellige Ausgabe an :-)

Kannst du mir das bitte erläutern wie ich das jetzt in meinem Beispiel 
umsetze?

Ist u jetzt der Wert den ich Umwandeln möchte oder die Anzahl der 
Null-Stellen?

von Karl H. (kbuchegg)


Lesenswert?

Lokus Pokus schrieb:

> Ist u jetzt der Wert den ich Umwandeln möchte oder die Anzahl der
> Null-Stellen?

Du verzeihst, dass ich schmunzle.

Der Funktionsaufruf lautet
1
  itoxxxx (buf, u);

buf ist recht offensichtlich das char Array, in welches die ASCII 
Repräsentierung rein soll.

Was also wird u sein, wenn die Funktion einen Wert in eine ASCII 
Darstellung umwandelt?

Und warum hat die Funktion, die einen uint16_t in eine ASCII-Hex 
Darstellung umwandelt (4 hexadezimale Ziffern) 4 Stück x im Namen, 
während eine Funktion itoxx, die einen unsigned char umwandelt (2 
hexadezimale Ziffern) nur 2 x im Namen hat?
Konsequenterweise hätte Frank die Funktionen allerdings itoXXXX und 
itoXX genannt, denn die ASCII Repräsentierungen werden ja mit 
Grossbuchstaben gebildet. Aber ... das sei ihm mal nachgesehen :-)

: Bearbeitet durch User
von Lokus P. (derschatten)


Lesenswert?

Dann muß ich für die Funktion itoxxxx bereits den umgewandelten HEX Wert 
angeben oder wie?
Oder ersetzt es das ursprüngliche itoa?

von DirkB (Gast)


Lesenswert?

Welchen Typ hat denn u in dem Beispiel?

von eProfi (Gast)


Lesenswert?

>     *xx++ = itox (i & 0x0F);
das &0x0F kann man weglassen, da es in itox eh gemacht wird.

Es geht auch Anders (aus dem Stegreif):
u16_t x;
hex[]="0123456789ABCDEF";
putch('0');putch('X');putch('0');
putch(hex[ x>>12   ]);
putch(hex[(x>>8)&15]);
putch(hex[(x>>4)&15]);
putch(hex[ x    &15]);

oder wenn man doch ein out-String will:
out[]="0x03456\0";
out[6]=hex[ x     &15];
out[5]=hex[(x>>=4)&15];
out[4]=hex[(x>>=4)&15];
out[3]=hex[ x>> 4    ];

von Karl H. (kbuchegg)


Lesenswert?

Lokus Pokus schrieb:
> Dann muß ich für die Funktion itoxxxx bereits den umgewandelten HEX Wert
> angeben oder wie?
> Oder ersetzt es das ursprüngliche itoa?

es ersetzt das ursprüngliche itoa.

Was ist denn so schwer drann einfach mal
1
...
2
  char s[20];
3
4
  itoxxxx( s, 15 );
5
  lcd_puts( s );

in ein Testprogramm zu schreiben und nachzusehen, ob danach
1
000F
auf dem LCD steht?
D.h. die Zahl, ausgedrückt als Hex-Zahl, mit Grossbuchstaben, und auf 4 
Stellen aufgeblasen.

: Bearbeitet durch User
von Lokus P. (derschatten)


Lesenswert?

Mehr oder weniger funktioniert das.
Allerdings habe ich noch ein unerwünschtes Verhalten.

Die komplette Schaltung soll mit einer 3V Lithium Zelle betrieben 
werden.

Wenn ich die Funktion nun verwende:
1
char s[7];
2
3
dogm_cursor(0,2);
4
dogm_puts("A: ");
5
itoxxxx(s, irmp_data.address);
6
dogm_puts(s);
7
dogm_puts(" C: ");
8
itoxxxx(s, irmp_data.command);
9
dogm_puts(s);

dann verstümmelt es mir die Anzeige nach ein paar Ausgaben. Im 
Netzbetrieb passiert das nicht.
Ist diese Funktion nun so Performancelastig das dabei der AVR in die 
Knie geht?

von Tor Tor Tor (Gast)


Lesenswert?

Lokus Pokus schrieb:
> lcd_puts(itoa(toupper(irmp_data.address),s,16));

lcd_puts(toupper(itoa(irmp_data.address,s,16)));

von Karl H. (kbuchegg)


Lesenswert?

Lokus Pokus schrieb:


> dann verstümmelt es mir die Anzeige nach ein paar Ausgaben.


Verstümmeln bedeutet?

> Im
> Netzbetrieb passiert das nicht.
> Ist diese Funktion nun so Performancelastig das dabei der AVR in die
> Knie geht?

Dem µC ist das grundsätzlich wurscht was er macht. Deswegen braucht er 
da auch nicht mehr Strom.

Schon mal frische Batterien probiert?

von Karl H. (kbuchegg)


Lesenswert?

Tor Tor Tor schrieb:
> Lokus Pokus schrieb:
>> lcd_puts(itoa(toupper(irmp_data.address),s,16));
>
> lcd_puts(toupper(itoa(irmp_data.address,s,16)));

falsch.

Können wir diesen Nebenschauplatz jetzt bitte in Frieden ruhen lassen?
Das 'Problem' ist schon längst gelöst.

(Falls es interessiert. Es ist deswegen falsch, weil toupper keinen 
String konvertiert, sondern ein einzelnes Zeichen.)

: Bearbeitet durch User
von Irgendwer (Gast)


Lesenswert?

Schaulus Tiger schrieb:
> ......

Interessant das ganze:
1
Syntax
2
3
#include <stdio.h>
4
int snprintf(char* buffer, size_t nsize, const char* fmt, ...);
5
int snwprintf(wchar_t* buffer, size_t nsize, const wchar_t* fmt, ...);
6
7
Beschreibung
8
9
Sendet formatierte Ausgabe an einen buffer, der die in nsize angegebene Maximalgröße hat. Ist die Anzahl der auszugebenden Bytes:
10
11
< nsize, so werden alle Zeichen einschließlich des abschließenden ‘\0’- Zeichens geschrieben.
12
13
== nsize, so werden nsize Zeichen ohne das abschließende ‘\0’-Zeichen geschrieben.
14
15
> nsize, so werden nsize Zeichen ohne das abschließende ‘\0’-Zeichen geschrieben.
16
Wenn nsize 0 ist, bleibt der String leer (und kann NULL sein).

Scheit also durchaus abhängig von der verwendeten Implementation der std 
zu sein.

Schaulus Tiger schrieb:
> zweifel (int zahl)
> {
> char  array[8];
> int   i;
>
>   snprintf (array, sizeof(array), "%d", zahl);
>   printf ("%10d -> ", zahl);
>   for (i = 0; i < 8; i++) {
>     printf (" %d", array[i]);
>   }
>   puts ("");
>   return;
> }

Deine Ausgabe eines Strings ist ein Witz.
Du begrenzt die Ausgabe Fix durch deine Feste Vorgabe in der For von 
Acht und wunderst dich über die Aussage.

Mach mal ein
1
printf (" %s", array);
die weiß nämlich nichts davon das sie nach acht Zeichen aufhören soll.

oder z.B.:
1
i=0;
2
do
3
{
4
  if (array[i])
5
    printf (" %d", array[i]);
6
  else break;
7
  ++i;
8
}while(1);

Sowie eine andere (String-)Funktion aufgerufen wird weiß diese nichts 
mehr davon das dass Array nur acht Zeichen groß ist (außer man übergibt 
mit sizeof diese Info) und läuft so lange bis es auf eine Null trifft.
1
Sehr lustig wir auch nach sowas z.B. eine strcat(array, "0123456");
 :-)

von asdfasd (Gast)


Lesenswert?

SCNR ;-)
1
char *
2
itoh(char *buf, int digits, unsigned number)
3
{
4
    for (buf[digits] = 0; digits--; number >>= 4)
5
        buf[digits] = "0123456789ABCDEF"[number & 15];
6
    return buf;
7
}

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


Lesenswert?

Irgendwer schrieb:
> Scheit also durchaus abhängig von der verwendeten Implementation der std
> zu sein.

Wir schreiben das Jahr 2015, und seit C99 ist snprintf() genormt:
1
  7.19.6.5 The snprintf function
2
  Synopsis
3
4
1         #include <stdio.h>
5
          int snprintf(char * restrict s, size_t n,
6
                  const char * restrict format, ...);
7
  Description
8
9
2 The snprintf function is equivalent to fprintf, except that the
10
  output is written into an array (specified by argument s) rather
11
  than to a stream. If n is zero, nothing is written, and s may be a
12
  null pointer. Otherwise, output characters beyond the n-1st are
13
  discarded rather than being written to the array, and a null
14
  character is written at the end of the characters actually written
15
  into the array. If copying takes place between objects that overlap,
16
  the behavior is undefined.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lokus Pokus schrieb:
> dann verstümmelt es mir die Anzeige nach ein paar Ausgaben.

Du hast vergessen, nach dem Aufruf von itoxxxx() den Buffer zu 
terminieren - so wie ich es im Beispiel von itoxxxx() auch verwendet 
habe.

Also:

   itoxxxx(s, irmp_data.command);
   buf[4] = '\0';

Das ist ein Unterschied zu itoa().

Anderenfalls kannst Du auch itoxxxx() (dann konsequenterweise auch 
itoxx()) selbst terminieren lassen:
1
static void
2
itoxx (char * xx, unsigned char i)
3
{
4
    *xx++ = itox (i >> 4);
5
    *xx++ = itox (i & 0x0F);
6
    *xx = '\0';               // NEU!
7
}
8
9
static void
10
itoxxxx (char * xx, unsigned int i)
11
{
12
    itoxx (xx, i >> 8);
13
    itoxx (xx + 2, i & 0x0FF);
14
    *(xx + 4) = '\0';               // NEU!
15
}

Dann brauchst Du nur

   itoxxxx(s, irmp_data.command);

aufzurufen und Du kannst Dir das:

   buf[4] = '\0';

schenken.

P.S.
In main.c des IRMP-Projekts sind genau diese itoxx()-Funktionen 
(mit interner Terminierung!) schon seit vielen Monaten vorhanden, um 
eine konkrete Anwendung von IRMP zu zeigen. Ich frage mich, wieso Du 
nicht sowieso darüber gestolpert bist.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Irgendwer schrieb:
> Beschreibung
>
> Sendet formatierte Ausgabe an einen buffer, der die in nsize angegebene
> Maximalgröße hat. Ist die Anzahl der auszugebenden Bytes:
>
> < nsize, so werden alle Zeichen einschließlich des abschließenden ‘\0’-
> Zeichens geschrieben.
>
> == nsize, so werden nsize Zeichen ohne das abschließende ‘\0’-Zeichen
> geschrieben.

Kannst Du dazu bitte eine Quelle nennen? Ich traue deutschen 
Übersetzungen von libc-Manuals nicht.

Das da oben beschriebene wäre das gleiche Verhalten, wie strncpy() es 
macht. Ich weiß aber, dass diese Implemenation für snprintf() dann 
falsch wäre.

> Scheit also durchaus abhängig von der verwendeten Implementation der std
> zu sein.

Nein, das ist ein Fehler. Es gibt Standards. Wenn diese nicht 
eingehalten werden, ist das einen Bug-Report wert.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

asdfasd schrieb:
1
> char *
2
> itoh(char *buf, int digits, unsigned number)
3
> {
4
>     for (buf[digits] = 0; digits--; number >>= 4)
5
>         buf[digits] = "0123456789ABCDEF"[number & 15];
6
>     return buf;
7
> }

Sehr elegante Lösung, gefällt mir um einiges besser als mein eigenes 
itoxxxx() und verbraucht zudem nur die Hälfte des Flashs :-)

Ich werde diese Version direkt in meine Libs so übernehmen.

Danke,

Frank

von Lokus P. (derschatten)


Lesenswert?

super und wie wendet man das nun wieder an?
"number" ist die Anzahl der Nullen?
Digits der HEX-Wert?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lokus Pokus schrieb:
> super und wie wendet man das nun wieder an?

Ist das wirklich so schwierig zu verstehen? Das erkennt man doch schon 
an den Typen und Namen der Argumente. Nimm Dir abends mal ein gutes 
C-Buch zur Hand. Grundlagen können nie schaden. Und wenn man das 
versteht, was man da anwendet, ist das auch nicht verkehrt.

> "number" ist die Anzahl der Nullen?

Nein.

> Digits der HEX-Wert?

nein.

number (deutsch "Zahl") ist die Zahl, die Du konvertieren willst.

digits (deutsch "Ziffern") ist die Anzahl der Ziffern, auf die die
       Ausgabe formatiert wird. Mit der Anzahl von Nullen hat das
       wirklich nichts zu tun. Bei 0x1234 gibts z.B. keine Nullen
       bei digits = 4. Jedoch gibts für die Zahl 0x12 genau 2 Nullen.
       Die Ausgabe ist dann nämlich "0012".

Hier hätte statt eines C-Buchs sogar ein Wörterbuch "deutsch-englisch" 
gereicht....

: Bearbeitet durch Moderator
von Schaulus Tiger (Gast)


Lesenswert?

Irgendwer schrieb:
> Interessant das ganze:
>
> Scheit also durchaus abhängig von der verwendeten Implementation der std
> zu sein.
>
> Schaulus Tiger schrieb:
>> zweifel (int zahl)
>> {
>> char  array[8];
>> int   i;
>>
>>   snprintf (array, sizeof(array), "%d", zahl);
>>   printf ("%10d -> ", zahl);
>>   for (i = 0; i < 8; i++) {
>>     printf (" %d", array[i]);
>>   }
>>   puts ("");
>>   return;
>> }
>
> Deine Ausgabe eines Strings ist ein Witz.
> Du begrenzt die Ausgabe Fix durch deine Feste Vorgabe in der For von
> Acht und wunderst dich über die Aussage.
>
> Mach mal ein
1
printf (" %s", array);
> die weiß nämlich nichts davon das sie nach acht Zeichen aufhören soll.

Doch, das merkt sie am '\0' Byte, das von einem korrekten snprintf eben 
immer eingefügt wird, siehe die witzige Ausgabe:

Schaulus Tiger schrieb:
1
     12345 ->  49 50 51 52 53 0 4 8
2
    123456 ->  49 50 51 52 53 54 0 8
3
   1234567 ->  49 50 51 52 53 54 55 0
4
  12345678 ->  49 50 51 52 53 54 55 0
5
 123456789 ->  49 50 51 52 53 54 55 0
6
  12345678 ->  49 50 51 52 53 54 55 0
7
   1234567 ->  49 50 51 52 53 54 55 0
8
    123456 ->  49 50 51 52 53 54 0 0

von fdghj (Gast)


Lesenswert?

Frank M. schrieb:
> buf[digits] = "0123456789ABCDEF"[number & 15];

hm, das hätte ich jetzt auf Anhieb auch nicht verstanden...
Ist das ein statisches Array?

von klausr (Gast)


Lesenswert?

fdghj schrieb:
>> buf[digits] = "0123456789ABCDEF"[number & 15];
>
> hm, das hätte ich jetzt auf Anhieb auch nicht verstanden...
> Ist das ein statisches Array?

Ich hätts so geschrieben:
1
char *
2
itoh (char *buf, int digits, unsigned number)
3
{
4
  const char hex[]="0123456789ABCDEF";
5
6
  for (buf[digits] = 0; digits--; number >>= 4)
7
    buf[digits] = hex[number & 15];
8
  return buf;
9
}

Aber die Lösung von asdfasd ist eleganter...

von W.S. (Gast)


Lesenswert?

Lokus Pokus schrieb:
> Ich möchte gerne einen HEX-Wert auf einem LCD in Großbuchstaben
> ausgeben.
>
> Jetzt hab ich schon folgendes Versucht:
> lcd_puts(itoa(toupper(irmp_data.address),s,16));
>
> Allerdings funkt das nicht.
>
> Geht das so überhaupt?

Manchmal ist mir zum Heulen ob des geistigen Zustandes unserer Schreiber 
hier. Sowas sollte doch eine dee allerleichtesten Fingerübungen für 
jeden Programmier-Anfänger sein - und doch ist es bereits den Leuten 
hier zu hoch.

Also, ich zitiere mal aus der Lernbetty (hier im Forum bereits 
sedimentiert..):

const char HexChars[17]   = {"0123456789ABCDEF"};

/* ein Hex-Zeichen ausgeben */
void Nibble_Out (int aHex)
{ V24_CharOut (HexChars[aHex & 0x0F]); }

/* ein Byte als Hexa ausgeben */
void HexB_Out (byte aHex)
{ Nibble_Out (aHex >> 4);
  Nibble_Out (aHex);
}

/* ein Word als Hexa ausgeben */
void HexW_Out (word aHex)
{ HexB_Out (aHex >> 8);
  HexB_Out (aHex);
}

/* ein DWORD als Hexa ausgeben */
void HexL_Out (long aHex)
{ HexW_Out (aHex >> 16);
  HexW_Out (aHex);
}

/* ein QWORD als Hexa ausgeben */
void HexQ_Out (int64* aHex)
{ HexL_Out (*aHex >> 32);
  HexL_Out (*aHex);
}

Aber bitte keine Anfragen, was denn die mysteriöse Funktion 
"V24_CharOut(char blabla)" denn wohl machen wird.

Noch ein Tip: Wer es lieber in Kleinbuchstaben mag, darf das Array 
"const char HexChars" umschreiben - sofern das keine geistige 
Überlastung nach sich zieht.

W.S.

von Lokus P. (derschatten)


Lesenswert?

Was macht denn nun diese Funktion: "{ V24_CharOut (HexChars[aHex & 
0x0F]); }" nun genau?

von Hans (Gast)


Lesenswert?

Frank M. schrieb:
> asdfasd schrieb:
>> char *
>> itoh(char *buf, int digits, unsigned number)
>> {
>>     for (buf[digits] = 0; digits--; number >>= 4)
>>         buf[digits] = "0123456789ABCDEF"[number & 15];
>>     return buf;
>> }
>
> Sehr elegante Lösung, gefällt mir um einiges besser als mein eigenes
> itoxxxx() und verbraucht zudem nur die Hälfte des Flashs :-)
>
> Ich werde diese Version direkt in meine Libs so übernehmen.
>
> Danke,
>
> Frank

Könnte beim AVR allerdings dauerhaft RAM für den String benötigen. Je 
nachdem, wie gut der Compiler optimiert. Hast Du das getestet?

Im Zweifel würde ich eher beim if bleiben:
1
char *
2
itoh(char *buf, int digits, unsigned number)
3
{
4
  for (buf[digits] = 0; digits--; number >>= 4) {
5
    unsigned char val = number & 0x0F;
6
    if (val <= 9) {
7
      val += '0';
8
    } else {
9
      val += 'A' - 10;
10
    }
11
    buf[digits] = val;
12
  }
13
  return buf;
14
}

von DirkB (Gast)


Lesenswert?

Wieviel Bytes soll das sparen?

von eProfi (Gast)


Lesenswert?

1
  for (buf[digits] = 0; digits--; number >>= 4) {
2
    unsigned char val = number & 0x0F;
3
    if (val <= 9) {
4
      val += '0';
5
    } else {
6
      val += 'A' - 10;
7
    }
8
    buf[digits] = val;
9
  }
das geht eleganter:
1
  for (buf[digits] = 0; digits--; number >>= 4) {
2
    unsigned char val = number & 0x0F;
3
    buf[digits] = '0'+val+(val>9?7:0);
4
  }
5
oder
6
  for (buf[digits] = 0; digits--; number >>= 4) {
7
    if((buf[digits] = '0'+(number & 0x0F))>'9'){buf[digits]+=7;}
8
  }
Eine while-Schleife wäre sowieso eleganter.

von DirkB (Gast)


Lesenswert?

Die Magic 7 stört da noch.

von Lokus P. (derschatten)


Lesenswert?

>   for (buf[digits] = 0; digits--; number >>= 4) {
>     if((buf[digits] = '0'+(number & 0x0F))>'9'){buf[digits]+=7;}
>   }
> [/c]
> Eine while-Schleife wäre sowieso eleganter.

Diese Variante benötigt 2 Bytes mehr im Flash

von eProfi (Gast)


Lesenswert?

> Die Magic 7 stört da noch.
Dann schreib halt 'A'-10-'0'  (65-10-48=7).

> Diese Variante benötigt 2 Bytes mehr im Flash
Als welche?
Da Compiler das Konstrukt ?: manchmal unglücklich übersetzen, probier 
mal:
  for (buf[digits] = 0; digits--; number >>= 4) {
    unsigned char val = '0'+(number & 0x0F);
    if(val > 9){val += 'A'-10-'0';}
    buf[digits] = val;


mit while schaut das dann so aus:
1
  buf[digits] = 0; //terminating \0
2
  do{
3
    unsigned char val = '0'+(number & 0x0F);
4
    if(val > 9){val += 'A'-10-'0';}
5
    buf[digits] = val;
6
    number >>= 4;
7
    while(--digits > 0);  //digits würde ich signed machen, damit 0 nicht 256 Durchläufe macht
8
  }
Wieviel Flash braucht das?
Jetzt wäre ein Vergleich der Listings interessant.

Da es alle meine Compiler umständlich machen, habe ich es gleich als 
Inline-Asm programmiert, da sind es wirklich nur ein paar Befehle.

von Hans (Gast)


Lesenswert?

Dein Code addiert bei Ziffern über 9 zuerst '0' und dann nochmal 7. 
Meine Version addiert nur einmal den richtigen Wert. Vermutlich ist das 
genau die zusätzliche Instruktion, die 2 Byte mehr Flash braucht.

Was daran eleganter sein soll, erschließt sich mir nicht so recht, aber 
das ist wohl Geschmackssache.

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.