mikrocontroller.net

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


Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
strtol()

Autor: bitte löschen (Gast)
Datum:

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

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Joachim K. (minifloat)
Datum:

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

Autor: Björn Cassens (bjoernc) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Wachtler (mfgkw)
Datum:

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

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

Autor: Björn Cassens (bjoernc) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: bitte löschen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ungeprüft:
void HexToDez(const char* sVon, char* sNach)
{
 long i,j;
 for (i = 0, j = 0; *sVon ; sVon++)
 {
  char c = *sVon;
  i = i << 4;
  if (c <= '9')
  {
   i |= c - '0';
  }
  else
  {
    c &= 0b11011111;
    i |= c - ('A' - 10);
  }
 }
 for (j = 1000000000; !(i / j); j /= 10);
 for (; j > 0 ; j /= 10)
 {
  *(sNach++) = '0' + i / j;
 }
 *sNach = 0;
}

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: mark (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);
}

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klasse,
es funktioniert! Vielen Dank Rufus!

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
summe *= 16^i;

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

Autor: bitte löschen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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):
#include <stdio.h> // für printf im Testaufruf

void HexToDez(const char* sVon, char* sNach)
{
  long i,j;
  for (i = 0; *sVon ; sVon++)
  {
    char c = *sVon;
    i = i << 4;
    if (c <= '9')
    {
      i |= c - '0';
    }
    else
    {
      c &= 0xdf;
      i |= c - ('A' - 10);
    }
  }
  for (j = 1000000000; !(i / j); j /= 10);
  for (; j > 0 ; j /= 10)
  {
    int k = (i / j);
    *(sNach++) = '0' + (char)k;
    i -= k * j;
  }
  *sNach = 0;
  return sNach;
}

int main()
{
  char sDez[11];
  printf("%s\n", HexToDez("1A9c", sDez));
  return 0;
}

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include<stdio.h>
#include<conio.h> //für putch()

long hexatoi(char*s){
  long r=0;//Result
  char n;  //Nibble
  while(*s){
    if((n=*s++ & 31)>15)
         n&=15; //0x30 .. 0x3F  '1' 31 --> 1
    else n+= 9; //0x40 .. 0x6f  'a' 61 --> 1 +9=10
    r=r*16+n;
    }
  return(r);
  }

void main(void){
  long wert = hexatoi("2710");
  char c;

  c=47;while(c++,(wert-=10000)>=0);putch(c);
  c=58;while(c--,(wert+= 1000)< 0);putch(c);
  c=47;while(c++,(wert-=  100)>=0);putch(c);
  c=58;while(c--,(wert+=   10)< 0);putch(c);
  putch(48+wert);//48, da bei ungerader Stellenzahl wert positiv ist
  }


Mit Unterdrückung führender Nullen und konstanter Ausgabelänge:
void main(void){
  long wert = hexatoi("2710");
  char c,l=' ';//Leading Char (Leerzeichen oder 0)

  c=-1;while(c++,(wert-=1000000000)>=0);if(c)l='0';putch(l+c);
  c=10;while(c--,(wert+= 100000000)< 0);if(c)l='0';putch(l+c);
  c=-1;while(c++,(wert-=  10000000)>=0);if(c)l='0';putch(l+c);
  c=10;while(c--,(wert+=   1000000)< 0);if(c)l='0';putch(l+c);
  c=-1;while(c++,(wert-=    100000)>=0);if(c)l='0';putch(l+c);
  c=10;while(c--,(wert+=     10000)< 0);if(c)l='0';putch(l+c);
  c=-1;while(c++,(wert-=      1000)>=0);if(c)l='0';putch(l+c);
  c=10;while(c--,(wert+=       100)< 0);if(c)l='0';putch(l+c);
  c=-1;while(c++,(wert-=        10)>=0);if(c)l='0';putch(l+c);
  putch(58+wert);//48+10=58, da bei gerader Stellenzahl wert hier negativ ist
  }

Mit Unterdrückung führender Nullen und variabler Ausgabelänge:
void main(void){
  long wert = hexatoi("2710");
  char c,l=' ';//Leading Char (Leerzeichen oder 0)

  c=-1;while(c++,(wert-=1000000000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
  c=10;while(c--,(wert+= 100000000)< 0);if(c)l='0';if(l!=' ')putch(l+c);
  c=-1;while(c++,(wert-=  10000000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
  c=10;while(c--,(wert+=   1000000)< 0);if(c)l='0';if(l!=' ')putch(l+c);
  c=-1;while(c++,(wert-=    100000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
  c=10;while(c--,(wert+=     10000)< 0);if(c)l='0';if(l!=' ')putch(l+c);
  c=-1;while(c++,(wert-=      1000)>=0);if(c)l='0';if(l!=' ')putch(l+c);
  c=10;while(c--,(wert+=       100)< 0);if(c)l='0';if(l!=' ')putch(l+c);
  c=-1;while(c++,(wert-=        10)>=0);if(c)l='0';if(l!=' ')putch(l+c);
  putch(58+wert);//48+10=58, da bei gerader Stellenzahl wert hier negativ ist
  }

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

Autor: bitte löschen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und noch ein Fehler.. :D
char* HexToDez(const char* sVon, char* sNach)
{
  char* p;
  long i,j;
  p = sNach;
  for (i = 0; *sVon ; sVon++)
  {
    char c = *sVon;
    i = i << 4;
    if (c <= '9')
    {
      i |= c - '0';
    }
    else
    {
      c &= 0xdf;
      i |= c - ('A' - 10);
    }
  }
  for (j = 1000000000; !(i / j); j /= 10);
  for (; j > 0 ; j /= 10)
  {
    int k = (i / j);
    *(sNach++) = '0' + (char)k;
    i -= k * j;
  }
  *sNach = 0;
  return p;
}

int main()
{
  char sDez[11];
  printf("%s\n", HexToDez("1A9c", sDez));
  return 0;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: bitte löschen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
char* HexToDez(const char* sVon, char* sNach)
{
  long tmp = hexToLong( sVon );
  return longToDez( tmp, sNach );
}

Zusammen mit weiteren Umwandlungsfunktionen entsteht so ein Baukasten, 
mit dem man sich die jeweils konkret benötigte ohne viele Umschweife 
leicht zusammenstellen kann.
char* BinToDez(const char* sVon, char* sNach)
{
  long tmp = binToLong( sVon );
  return longToDez( tmp, sNach );
}

char* HexToBin(const char* sVon, char* sNach)
{
  long tmp = hexToLong( sVon );
  return longToBin( tmp, sNach );
}

....

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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.