itoa in Großbuchstaben ausgeben

Gast #4027772
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);
Gast #4027923
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
  }
Moderator Persönliche Seite #4027935
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'
Moderator Persönliche Seite #4027975
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.
Gast #4028035
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.
Gast #4028056
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!
Gast #4028097
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.
Moderator Persönliche Seite #4028143
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.
Gast #4028526
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...
Moderator Persönliche Seite #4028543
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.
Moderator Persönliche Seite #4028547
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.
Moderator Persönliche Seite #4028569
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 :-)
Moderator Persönliche Seite #4028607
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.
#4028616
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.
OP #4030700
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?
#4030706
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 :-)
Gast #4030809
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    ];
#4030848
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.
OP #4030950
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?
#4031117
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.)
Gast #4031171
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");
 :-)
Moderator Persönliche Seite #4031258
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.
Moderator Persönliche Seite #4031265
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.
Moderator Persönliche Seite #4031266
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.
Moderator Persönliche Seite #4031322
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
Moderator Persönliche Seite #4031440
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....
Gast #4031508
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
Gast #4031942
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...
Gast #4032057
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.
Gast #4032878
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
}
Gast #4033150
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.
Gast #4034160
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.
Gast #4034651
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren