Forum: Mikrocontroller und Digitale Elektronik Umwandlung von ASCII-Zeichen, die Hexzahlen darstellen


von Klaus (Gast)


Lesenswert?

Hallo zusammen,
ich möchte gerne ASCII-Zeichen eines Strings, die Hexzahlen dastellen, 
in Dezimalzahl umwandeln.

Also:

Buffer[4]== '2'
Buffer[5]== '7'
Buffer[6]== '1'
Buffer[7]== '0'

2710(hex) = 10000(dec)!

wie kann ich das am besten in C bewerkstelligen?
Grüße

von ich (Gast)


Lesenswert?

strtol()

von bitte löschen (Gast)


Lesenswert?

In welcher Form willst Du die Dezimalzahl haben? BCD, packed BCD oder 
als fertigen String?

von Klaus (Gast)


Lesenswert?

Hallo Philipp,
ich bräuchte die Dezimalzahl als fertigen String. Mit Hilfe einer 
for-Schleife würde ich die benötigten ASCII-Zeichen in ein char laden.

Nun habe ich ja "2710". Gibt es da schon ne fertige Funktion die mir das 
in 10.000(dec) umwandelt bzw. wie muss ich vorgehen? Ich meine mich zu 
erinnern, dass strtol() das nicht kann.
Grüße

von Achim M. (minifloat)


Lesenswert?

Klaus schrieb:
> strtol()
kann man da nicht sscanf() und sprintf() nehmen?
mfg mf

von Björn C. (bjoernc) Benutzerseite


Lesenswert?

Man kann dies auch selbst recht fix implementieren, man muss halt immer 
Modulo 10 teilen und das Ergebnis mit 0x30 addieren. Dieses wird solange 
wiederholt bis das Ende der Zahl erreicht ist. Ähnlich wird es bei 
char-Arrays gemacht- jedoch mit dem Unterschied das die 0x30 abgezogen 
werden müssen. Das Ende des Strings wird erreicht wenn der ausgegebene 
Wert "\0" entspricht. Printf und Scanf, dort wäre mir das in der Form 
nicht bekannt.

von Klaus W. (mfgkw)


Lesenswert?

Björn Cassens schrieb:
> das Ergebnis mit 0x30 addieren

das geht auch für Hexen? Oder nur mit zusätzlicher Hexerei?

von Björn C. (bjoernc) Benutzerseite


Lesenswert?

bei hexadezimal müsste man alles über 9 dann entsprechend mit A...F 
ersetzen. Auch dies könnte man mittels eines Offsets realisieren. 
Entsprechend muss man dann beim Modulo nicht mehr die Konstante 10 
sondern 16 benutzen.

Wobei die verschiedenen Darstellungen können bei printf und scanf 
entsprechend angepasst werden. Im wesentlichen muss der String in einen 
Int umgewandelt werden. Alles andere kann mittels printf usw. realisiert 
werden.

von bitte löschen (Gast)


Lesenswert?

Ungeprüft:
1
void HexToDez(const char* sVon, char* sNach)
2
{
3
 long i,j;
4
 for (i = 0, j = 0; *sVon ; sVon++)
5
 {
6
  char c = *sVon;
7
  i = i << 4;
8
  if (c <= '9')
9
  {
10
   i |= c - '0';
11
  }
12
  else
13
  {
14
    c &= 0b11011111;
15
    i |= c - ('A' - 10);
16
  }
17
 }
18
 for (j = 1000000000; !(i / j); j /= 10);
19
 for (; j > 0 ; j /= 10)
20
 {
21
  *(sNach++) = '0' + i / j;
22
 }
23
 *sNach = 0;
24
}

von Tom (Gast)


Lesenswert?

Wenn da allerdings jetzt ein Wert von A6B7C auftaucht, wie wird das 
bspw. mit atoi() geregelt? Also wenn ich jetzt 'A' in einen Integer 
umwandeln will...erhält der dann automatisch den Wert 10? sprich 
10611712? Ich behandle nämlich derzeit in etwa die selbe Problematik.
VG

von mark (Gast)


Lesenswert?

Hallo,
Hex-String zu Dezimal-String!

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
char s[] = "0D76";
unsigned long x;
x = strtoul(s, 0, 16);

printf("The value represented by the string \"%s\" is\n"

"%lu (decimal)\n" "%#lo (octal)\n" "%#lx (hex)\n",s, x, x, x);
return 0;
}

von Klaus (Gast)


Lesenswert?

Hallo,
vielen Dank für die Tipps und Hinweise. Ich habe nun mal was probiert. 
Allerdings will es noch nicht so richtig funktionieren.

Hier gibt es viele erfahrene Programmierer, für die es sicherlich ein 
Klacks ist. Allerdings, ich als Anfänger, habe so meine Mühen. Ich 
möchte ja den String 2710(hex) inden String 10000(dez) überführen und 
über die serielle Schnittstelle wieder ausgeben.

Zu Marks Beitrag: Lässt sich diesr printf-Varaiante auch bei der 
seriellen Übertragung einsetzen?



unsigned int hexatoi(const char * s)  {

  unsigned int  i,summe;

  summe = 0;
  for (i=0;i<=3;i++)
    {
      summe *= 16^i;
      if ((s[i] >= '0') && (s[i] <= '9'))
      summe += (s[i] - '0');

      if ((s[i] >= 'A') && (s[i] <= 'F'))
      summe += (s[i] - 'A' + 10);
    }

  return(sum);
}

int main(void){

char wert;

wert = (char)hexatoi("2710");

send_string(wert);
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Klaus schrieb:
> int main(void){
>
> char wert;
>
> wert = (char)hexatoi("2710");
>
> send_string(wert);
> }


Das geht so nicht. Einerseits ist ein char vom Wertebereich nicht 
ausreichend, um den Wert 0x2710 aufnehmen zu können (je nach 
Vorzeichen/nicht-Vorzeichen -128..+127 oder 0..255).

Dazu kommt, daß Du anzunehmen scheinst, daß "hexatoi" eine Zeichenkette 
zurückgibt (auch wenn Du versuchst, statt der Zeichenkette nur ein 
einzelnes Zeichen zu verwenden), das aber tut es nicht.

Du musst Deine Aktivität in zwei Schritte zerlegen:

1. Bestimme den Wert des "Hexstrings", also den Wert der als 
Zeichenfolge vorliegenden Zahl in hexadezimaler Notation.

Das macht "hexatoi". Der zurückgegebene Wert ist ein vorzeichenloser 
int, also ein 16-Bit-Wert. Kein char!

2. Wandle diesen Wert in einen "Dezimalstring" um, also in eine 
Zeichenfolge, die die Zahl in dezimaler Notation wiedergibt.

Dazu benötigst Du Speicherplatz für den "Dezimalstring", dafür benötigst 
Du Speicher. Der größte mit einer vorzeichenlosen 16-Bit-Zahl 
darstellbare Wert ist 65535, das sind fünf Zeichen. Dazu kommt das 
Stringendezeichen, also muss der Speicher für diese Zeichenkette 
mindestens 6 Zeichen lang sein.

Die Umwandlung erledigt entweder eine der /printf/-Varianten (hier: 
sprintf) oder aber eine von Dir selbst zu schreibende 
/uitoa/-Funktion.

3. Sende den Inhalt dieses "Dezimalstrings" über Deine serielle 
Schnittstelle irgendwohin.

"send_string" scheint dafür ausgelegt zu sein.

von Malte (Gast)


Lesenswert?

Klasse,
es funktioniert! Vielen Dank Rufus!

von eProfi (Gast)


Lesenswert?

summe *= 16^i;

Überlege Dir mal, was diese Zeile macht, bestimmt nicht das, was Du 
wolltest.

von bitte löschen (Gast)


Lesenswert?

Klaus schrieb:
> Allerdings will es noch nicht so richtig funktionieren.

Jo, da war ja auch noch ein kleiner Bug drin.

hier die korrigierte Version (mit Testaufruf):
1
#include <stdio.h> // für printf im Testaufruf
2
3
void HexToDez(const char* sVon, char* sNach)
4
{
5
  long i,j;
6
  for (i = 0; *sVon ; sVon++)
7
  {
8
    char c = *sVon;
9
    i = i << 4;
10
    if (c <= '9')
11
    {
12
      i |= c - '0';
13
    }
14
    else
15
    {
16
      c &= 0xdf;
17
      i |= c - ('A' - 10);
18
    }
19
  }
20
  for (j = 1000000000; !(i / j); j /= 10);
21
  for (; j > 0 ; j /= 10)
22
  {
23
    int k = (i / j);
24
    *(sNach++) = '0' + (char)k;
25
    i -= k * j;
26
  }
27
  *sNach = 0;
28
  return sNach;
29
}
30
31
int main()
32
{
33
  char sDez[11];
34
  printf("%s\n", HexToDez("1A9c", sDez));
35
  return 0;
36
}

von eProfi (Gast)


Lesenswert?

Ich würde die Möglichkeit vorsehen (wie bei &=df geschehen), dass statt 
der Großbuchstaben auch Kleinbuchstaben funktionieren:


So geht es eleganter, macht in der esten Version keine Unterdrückung 
führender Nullen  und 5 Stellen:
1
#include<stdio.h>
2
#include<conio.h> //für putch()
3
4
long hexatoi(char*s){
5
  long r=0;//Result
6
  char n;  //Nibble
7
  while(*s){
8
    if((n=*s++ & 31)>15)
9
         n&=15; //0x30 .. 0x3F  '1' 31 --> 1
10
    else n+= 9; //0x40 .. 0x6f  'a' 61 --> 1 +9=10
11
    r=r*16+n;
12
    }
13
  return(r);
14
  }
15
16
void main(void){
17
  long wert = hexatoi("2710");
18
  char c;
19
20
  c=47;while(c++,(wert-=10000)>=0);putch(c);
21
  c=58;while(c--,(wert+= 1000)< 0);putch(c);
22
  c=47;while(c++,(wert-=  100)>=0);putch(c);
23
  c=58;while(c--,(wert+=   10)< 0);putch(c);
24
  putch(48+wert);//48, da bei ungerader Stellenzahl wert positiv ist
25
  }


Mit Unterdrückung führender Nullen und konstanter Ausgabelänge:
1
void main(void){
2
  long wert = hexatoi("2710");
3
  char c,l=' ';//Leading Char (Leerzeichen oder 0)
4
5
  c=-1;while(c++,(wert-=1000000000)>=0);if(c)l='0';putch(l+c);
6
  c=10;while(c--,(wert+= 100000000)< 0);if(c)l='0';putch(l+c);
7
  c=-1;while(c++,(wert-=  10000000)>=0);if(c)l='0';putch(l+c);
8
  c=10;while(c--,(wert+=   1000000)< 0);if(c)l='0';putch(l+c);
9
  c=-1;while(c++,(wert-=    100000)>=0);if(c)l='0';putch(l+c);
10
  c=10;while(c--,(wert+=     10000)< 0);if(c)l='0';putch(l+c);
11
  c=-1;while(c++,(wert-=      1000)>=0);if(c)l='0';putch(l+c);
12
  c=10;while(c--,(wert+=       100)< 0);if(c)l='0';putch(l+c);
13
  c=-1;while(c++,(wert-=        10)>=0);if(c)l='0';putch(l+c);
14
  putch(58+wert);//48+10=58, da bei gerader Stellenzahl wert hier negativ ist
15
  }

Mit Unterdrückung führender Nullen und variabler Ausgabelänge:
1
void main(void){
2
  long wert = hexatoi("2710");
3
  char c,l=' ';//Leading Char (Leerzeichen oder 0)
4
5
  c=-1;while(c++,(wert-=1000000000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
6
  c=10;while(c--,(wert+= 100000000)< 0);if(c)l='0';if(l!=' ')putch(l+c);
7
  c=-1;while(c++,(wert-=  10000000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
8
  c=10;while(c--,(wert+=   1000000)< 0);if(c)l='0';if(l!=' ')putch(l+c);
9
  c=-1;while(c++,(wert-=    100000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
10
  c=10;while(c--,(wert+=     10000)< 0);if(c)l='0';if(l!=' ')putch(l+c);
11
  c=-1;while(c++,(wert-=      1000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
12
  c=10;while(c--,(wert+=       100)< 0);if(c)l='0';if(l!=' ')putch(l+c);
13
  c=-1;while(c++,(wert-=        10)>=0);if(c)l='0';if(l!=' ')putch(l+c);
14
  putch(58+wert);//48+10=58, da bei gerader Stellenzahl wert hier negativ ist
15
  }

Statt putch kann ein neuer String aufgebaut werden: s=s+c;

von bitte löschen (Gast)


Lesenswert?

Und noch ein Fehler.. :D
1
char* HexToDez(const char* sVon, char* sNach)
2
{
3
  char* p;
4
  long i,j;
5
  p = sNach;
6
  for (i = 0; *sVon ; sVon++)
7
  {
8
    char c = *sVon;
9
    i = i << 4;
10
    if (c <= '9')
11
    {
12
      i |= c - '0';
13
    }
14
    else
15
    {
16
      c &= 0xdf;
17
      i |= c - ('A' - 10);
18
    }
19
  }
20
  for (j = 1000000000; !(i / j); j /= 10);
21
  for (; j > 0 ; j /= 10)
22
  {
23
    int k = (i / j);
24
    *(sNach++) = '0' + (char)k;
25
    i -= k * j;
26
  }
27
  *sNach = 0;
28
  return p;
29
}
30
31
int main()
32
{
33
  char sDez[11];
34
  printf("%s\n", HexToDez("1A9c", sDez));
35
  return 0;
36
}

von Karl H. (kbuchegg)


Lesenswert?

Philipp Klostermann schrieb:
> Und noch ein Fehler.. :D

Die kann man vermeiden oder zumindest reduzieren, indem man nicht eine 
einzige große Eierlegende-Wollmilchsau-Universalfunktion schreibt, 
sondern sich die komplette Aufgabe in einfachere Teilaufgaben zerlegt 
und für jede Teilaufgabe eine eigene Funktion schreibt.

von bitte löschen (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die kann man vermeiden oder zumindest reduzieren, indem ..
Oder indem man sich die Mühe macht, das auch mal zu kompilieren, bevor 
man es ins Forum stellt. Der Fehler war ein falscher Rückgabetyp im 
Funktionskopf, wofür sich die Fehler-Wahrscheinlichkeit im Falle der 
Verwendung zweier Funktionen verdoppelt hätte, und die nicht-Verwendung 
einer Temporären Variable zum Durchreichen des 2. Parameters an den 
Rückgabewert, was durch die Verwendung zweier Funktionen auch nicht 
vermieden worden wäre.
Ich stimme Dir grundsätzlich zu, dass es besserer Programmierstil ist, 
große Funktionen aufzuteilen, aber das, worum es hier geht, ist doch 
etwas zu einfach und klein, um noch weiter aufgeteilt zu werden. (Die 
übliche Vorgabe aus meiner beruflichen Erfahrung ist, dass eine Funktion 
nicht größer als eine Bildschirmseite sein sollte, was ich wiederum für 
übertrieben und vor allen Dingen für zu pauschal halte.)

von Karl H. (kbuchegg)


Lesenswert?

Philipp Klostermann schrieb:

> Ich stimme Dir grundsätzlich zu, dass es besserer Programmierstil ist,
> große Funktionen aufzuteilen, aber das, worum es hier geht, ist doch
> etwas zu einfach und klein, um noch weiter aufgeteilt zu werden.

Gerade hier sind wir dann anderer Ansicht

Die Aufgabe lässt sich wunderbar aufteilen in:

Aus dem HEX-String eine tatsächliche Zahl zu machen
Aus der Zahl einen Dezimal-String generieren.

Da beides für sich alleine gesehen durchaus sinnvolle Einzelkomponenten 
sind, macht es auch Sinn die beiden Teile getrennt zu behandeln.
1
char* HexToDez(const char* sVon, char* sNach)
2
{
3
  long tmp = hexToLong( sVon );
4
  return longToDez( tmp, sNach );
5
}

Zusammen mit weiteren Umwandlungsfunktionen entsteht so ein Baukasten, 
mit dem man sich die jeweils konkret benötigte ohne viele Umschweife 
leicht zusammenstellen kann.
1
char* BinToDez(const char* sVon, char* sNach)
2
{
3
  long tmp = binToLong( sVon );
4
  return longToDez( tmp, sNach );
5
}
6
7
char* HexToBin(const char* sVon, char* sNach)
8
{
9
  long tmp = hexToLong( sVon );
10
  return longToBin( tmp, sNach );
11
}
12
13
....

Man kann das nicht früh genug lernen, dass sinnvolle Modularisierung 
einer der Schlüssel zu einem guten, tragfähigen Programmierstil ist.
Es ist einer der Schlüssel, warum die Unix-Shells so überaus erfolgreich 
und leistungsfähig sind.

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.