Hex to Dec -> C

OP #7305236
Lesenswert?

Hallo,

ich hab eine Denkblockade.

folgendes Problem

ich kriege die Sekunden von einer App als Hex Wert gesendet.

Beispiel: 54 sec

wird gesendet als int mit Wert 84[Dec] was einer 54[Hex] entspricht.

Wie kriege ich jetzt die 54[Hex] in eine 54[Dec] gewandelt?

Meine Idee wäre es die 84 als Hexadezimalen string zu printen und dann den String in ein Int umwandeln.

Gibts da was schöneres?

Beitrag #7305249 wurde von einem Moderator gelöscht.
#7305260
Lesenswert?

Lothar M. schrieb:

Wie kriege ich jetzt die 54[Hex] in eine 54[Dec] gewandelt?

Eine Wandlung ist evtl. gar nicht nötig, denn das ist beide Males die selbe Bitfolge: "0101_0100". Nur jeweils anders dargestellt.

Ich denke Lothar hat recht. Du bekommt ein gepacktes BCD Format. 4 Bit für die Zehnerstelle und 4 Bit für die Einer Stelle. Nur dein Programm oder das Programm mit dem du dir das anschaust erwartet eine normale 8 Bit binärzahl und zeigt die entsprechend an.

Beispiel:

24 Sekunden werden als 0010 0100 (2 4) ausgegeben. Für dein Programm ist das aber eine 00100100, also eine 36.

Moderator (Firma: Titel) Persönliche Seite #7305271
Lesenswert?

Oliver S. schrieb:

Da kommt wirklich der Dezimalwert des Hex-Wert in einem int? Wer macht denn sowas?

RTC-Uhren machen sowas.

Udo S. schrieb:

Lothar M. schrieb:

Wie kriege ich jetzt die 54[Hex] in eine 54[Dec] gewandelt?

Eine Wandlung ist evtl. gar nicht nötig, denn das ist beide Males die selbe Bitfolge: "0101_0100". Nur jeweils anders dargestellt.

Ich denke Lothar hat recht.

Sorry, ich habe meinen Post gelöscht, weil ich nach wiederholtem Lesen der Beschreibung vermute (wie Michael O. auch), dass da tatsächlich ein Packed-BCD-Wert ankommt.

EDTI: allgemein bekannt ist die Lösung als "bcd2bin". Da gibts dann einige Google-Treffer. Speziell auch im Bezug auf RTC:

OP #7305299
Lesenswert?

Oliver S. schrieb:

Da kommt wirklich der Dezimalwert des Hex-Wert in einem int? Wer macht denn sowas?

Lothar M. schrieb:

RTC-Uhren machen sowas.

Genau so sieht es aus. Damit wurde eine RTC gestellt. Die RTC soll nun in Software abgebildet werden. Und die Software erwartet Dezimal werte.

Oliver S. schrieb:

Wenns wirklich so ist, rechne halt zu Fuß um: abs(84/16) *10 + Rest *16

Geil! Vielen Dank auf sowas hatte ich gehofft. Kurz nachgerechnet passt es. Ich probiere es gleich mal aus.

Gast #7305309
Lesenswert?

John P. schrieb:

Oliver S. schrieb:

Wenns wirklich so ist, rechne halt zu Fuß um: abs(84/16) *10 + Rest *16

Geil! Vielen Dank auf sowas hatte ich gehofft. Kurz nachgerechnet passt es. Ich probiere es gleich mal aus.

???

Sollte das nicht eher (84/16)*10+Rest sein?

Also (84/16)×10+84%16 oder gleichwertig

Michael O. schrieb:

OutVal = (BCDVal >> 4) * 10 + (BCDVal & 0x0F);

#7305321
Lesenswert?

A. S. schrieb:

Sollte das nicht eher (84/16)*10+Rest sein?

Also (84/16)×10+84%16 oder gleichwertig

genau. Mit deder Multiplikation des Restes der Division mit 16 muss es natürlich schief gehen. und das abs() tut auch nicht Not. Sollte ja alles positiv sein :-)

Und um die (rechenintensivere) Division mit Restbildung zu umgehen shiftet man einfach die oberen 4 bit nach rechts und maskiert die oberen 4 bit für die Addition der Einerstelle aus.

Gruß Micha

Gast #7305405
Lesenswert?

Ich hatte mir mal für die Umwandlung DEZ ←→ BCD folgendes gebastelt:

1
 uint8_t bcd_to_dez (uint8_t bcd)
2
 {
3
   uint8_t einer = (bcd & 0x0F);
4
   uint8_t zehner = (((bcd >> 4) & 0x0F) * 10);
5
   return (einer+zehner); 
6
 }
7
/***********************************************************************/
8
 uint8_t dez_to_bcd (uint8_t dez)
9
 {
10
    uint8_t hex_zehner = dez/10; 
11
    uint8_t hex_einer = dez%10;
12
    return hex_einer + (hex_zehner << 4);
13
 }

bcd_to_dez deckt sich mit dem Vorschlag von Michael O.; er hat es nur etwas kompakter geschrieben ...

Gast #7306119
Lesenswert?

Das hat mit CHatGPT ausgegeben:

1
#include <stdio.h>
2
#include <stdlib.h>
3

4
int hex_to_decimal(int hex) {
5
  int decimal = 0;
6
  int digit;
7
  while (hex > 0) {
8
    digit = hex % 10;
9
    decimal = (decimal * 16) + digit;
10
    hex /= 10;
11
  }
12
  return decimal;
13
}

"Die Funktion nutzt eine Schleife, um durch die Ziffern der Hexadezimalzahl zu iterieren. Sie nimmt die letzte Ziffer der Hexadezimalzahl, indem sie den Rest von hex durch 10 dividiert, und fügt sie zur Dezimalzahl hinzu. Dann teilt sie hex durch 10, um zur nächsten Ziffer zu gelangen. Die Schleife wird fortgesetzt, bis hex 0 ist."

Gast #7306121
Lesenswert?

Und das macht ChatGPT bei BCD to Dez:

1
#include <stdio.h>
2

3
int bcd_to_decimal(int bcd) {
4
  int decimal = 0;
5
  int digit;
6
  int multiplier = 1;
7
  while (bcd > 0) {
8
    digit = bcd % 10;
9
    decimal += digit * multiplier;
10
    multiplier *= 10;
11
    bcd /= 10;
12
  }
13
  return decimal;
14
}

Und hier eine hex-bcd to dez:

1
#include <stdio.h>
2
#include <stdlib.h>
3

4
int hex_bcd_to_decimal(int hex_bcd) {
5
  int decimal = 0;
6
  int digit;
7
  int multiplier = 1;
8
  while (hex_bcd > 0) {
9
    digit = hex_bcd % 10;
10
    decimal += digit * multiplier;
11
    multiplier *= 16;
12
    hex_bcd /= 10;
13
  }
14
  return decimal;
15
}
Moderator (Firma: Titel) Persönliche Seite #7306160
Lesenswert?

Leo schrieb:

hex_bcd_to_decimal

Das Ding macht aber nicht, was der Funktionsname vermuten lässt, sondern die Funktion wandelt Binär/Dezimal (die Bitmuster sind ja für Binär- und Dezimalzahlen sowieso gleich) nach Packed-BCD.

Sie sollte also bin_to_bcd oder decimal_to_bcd (oder eben wie üblich kurz bin2bcd) heißen, und zum Schluss müsste somit stehen "return bcd;"

Gast #7306164
Lesenswert?

Ja, dass man den Mod-Wert, bzw. die einzelnen Mod-Werte bei der Umwandlung auf den Stack pushen kann, bzw. in einen String schieben, um dann die Liste der Modwerte umgekehrt nach oben auszulesen, ist hier ein wenig untergegangen, oder nicht?

Ein anderer Punkt ist, bei so Uhren müsste man eigentlich noch zu einem 60er System übersetzen.

50/80 ist deswegen schwierig (bzw. sehr leicht), weil die Zahlensysteme (also hier Hexi und Dezi) gewisse Ähnlichkeiten haben. Ich vermute mal, diese Zusatzinfogeschichte hat die Verwirrung ausgelöst. Ist ja auch nicht uninteressant ;)

Die Hexwerte selber helfen, sofort die Bitwerte zu sehen. Man könnte also auch von den Bits her nach Dezi übersetzen. Oder eben erstmal von Hex nach Bits.

BCD-Zahlen sind noch mal eine ganz andere Rechnung. Das sind einfach die nomalen Dezimalen Zahlen also solche im Rechner abgebildet. ABCDEF (wie im Hexadezimalsystem gibt es da nicht und die Umrechnung ist aufwendig, aber teilweise gibt es Hardwarebeschleunigungen.

Was hier auch noch fehlt, wären ein paar Zusatzbeispiel für die Ausgabe. Bei 54/84 sehe ich nur Hex/Dez-Werte und eine ungefragte Konvertierung - was ja nun auch der ghci so gerne macht, wenn man einfach mit Hexwerten rechnen möchte.

Moderator #7306179
Lesenswert?

Leo schrieb:

Und das macht ChatGPT bei BCD to Dez: ...

Die Funktion bcd_to_decimal kann optimiert werden zu

1
int bcd_to_decimal(int bcd) {
2
  return bcd > 0 ? bcd : 0;
3
}

Was war denn diesbezüglich deine Anfrage an ChatGPT? Der Funktionsname (bcd_to_decimal) klingt ja im Zusammenhang mit der Signatur (int -> int) schon etwas unsinnig.

Moderator (Firma: Titel) Persönliche Seite #7306202
Lesenswert?

rbx schrieb:

50/80 ist deswegen schwierig

Besser wären evtl. 49 Sekunden = 0x49 = 01001001bin = 73dez gewesen...

Yalu X. schrieb:

Die Funktion bcd_to_decimal kann optimiert werden

Sollte wohl bcd /= 16; statt bcd /= 10; heißen...

(int -> int) Ich würde dann wenigstens unsigned int erwartet. Denn BCD-Zahlen an sich können nicht negativ sein.

Gast #7306212
Lesenswert?

Lothar M. schrieb:

rbx schrieb:

Lothar M. schrieb:

Yalu X. schrieb:

John P. schrieb:

ich hab eine Denkblockade.

Und der ganze Thread bloß weil der John sein Gehirn nicht angeworfen gekriegt hatte. Es ist wirklich erschreckend, wie sehr es hier an Grundlagenwissen fehlt. Aber ungeachtet dessen wollen eben dieselben Leute mit ihrem Steckbrett, Arduino oder ST-Cube-Zeugs zum Mond fliegen oder etwas gleichgroßes veranstalten. und unter

C.K. schrieb:

https://cplusplus.com/reference/cstdlib/strtol/

macht man's heutzutage nicht mehr.

W.S.

Gast #7306845
Lesenswert?

Darf ich noch was aus dem ghci nachreichen? Nur um Missverständnisse zu vermeiden (man kann nämlich leicht durcheinanderkommen). Bei kleinen Werten braucht man nur durch 16 teilen und den Rest draufzählen.

1
[rbx@fe1 ~]$ ghci
2
GHCi, version 8.8.4: https://www.haskell.org/ghc/  :? for help
3
Prelude> let hexzuruk ab = (div ab 16, mod ab 16)
4
Prelude> hexzuruk 84
5
(5,4)
6

7
Prelude> hexzuruk 73
8
(4,9)

Da darf man dann nicht vergessen/übersehen, dass da normalerweise noch abcdef kommt, die aber bei bei dieser Art von Rückkonvertierung kaum noch eine Rolle spielen.

1
Prelude> hexzuruk 74
2
(4,10)
3

4
Prelude> 0x53 + 0x1
5
84
6
;)
#7306859
Lesenswert?

Früher hat man Uhren oder DCF77-Decoder noch ohne MC und nur mit TTL-ICs gemacht. Daher das gepackte BCD-Format. Irgendwie kriegt man das aus den Hirnen aber nicht wieder raus, daher ist es selbst in den neuesten MCs noch drin. Daher muß jeder PC beim Einschalten erstmal das veraltete BCD-Format aus der RTC lesen und in 64Bit Sekunden umrechnen.

Nur ganz wenige RTCs haben 32Bit oder 64Bit Sekunden für direkte Verarbeitung (Vergleiche, Zeitstempel von Dateien usw.).

Moderator #7306963
Lesenswert?

rbx schrieb:

Darf ich noch was aus dem ghci nachreichen?

Warum? Der TE suchte nach eine Lösung in C und die hat er längst bekommen.

Aber wenn schon Haskell, dann machen wir das mal richtig :)

Prelude> let hexzuruk ab = (div ab 16, mod ab 16)

Div und mod kann man zusammenfassen:

1
hexzuruk ab = divMod ab 16

Prelude> hexzuruk 84 (5,4)

Der TE will das Ergebnis nicht als Paar von zwei Ziffern, sondern als eine Integerzahl (im konkreten Fall 54). Das würde dann bspw. so aussehen:

1
bcd2bin bcd = 10 * high + low
2
              where (high, low) = divMod bcd 16

Die Umkehrfunktion wäre entsprechend

1
bin2bcd bin = 16 * high + low
2
              where (high, low) = divMod bin 10

Wenn man möchte, kann man das auch pointfree (also ohne explizites Funktionsargument) schreiben und dabei zudem die Hilfsvariablen high und low eliminieren:

1
bcd2bin' = uncurry ((+) . (10 *)) . flip divMod 16
2

3
bin2bcd' = uncurry ((+) . (16 *)) . flip divMod 10

Natürlich könnte die Zerlegung des BCD-Bytes in zwei Nibbles statt mit einer Division auch mit shiftR und .&. erfolgen, aber das war dir wohl zu C-ish ;-)

Gast #7307053
Lesenswert?

Yalu X. schrieb:

aber das war dir wohl zu C-ish ;-)

Eigentlich nicht, ich weiß ja, wie man es in asm macht. Aber das Beispiel mit dem uncurry finde ich schon gut. Auch wenn es natürlich die Schwierigkeit bis Unmöglichkeit der Übersetzung ein wenig verschleiert. Die Frage ist doch: wenn die Ausgangszahlen Dezimalzahlen sind, warum bleiben die das nicht? Zahlensysteme sind immer eindeutig. Doppelte Zahlen kommen da nicht vor. Die hätte man aber, wenn man abcdef nicht konkret berücksichtigt. 74 ist nicht 50, sondern 7A.

Mir ging es eher darum, darauf hinzuweisen, wie man Denkblockaden umgehen kann, beim Hin - und Herkonvertieren nicht durcheinander kommt, und die gelegentliche Schönheit des Hexadezimalsystems nicht übersieht, und ansonsten auch nur um ein wenig Austausch und die Dinge nicht allzu ernst nehmen ;)

Gast #7307094
Lesenswert?

Das macht es auch nicht besser. Wenn man das ausgiebt kommt "J" heraus.

Meine Kenntnisse in C sind rudimentär. Aber es sollten doch einfache Anweisungen zur Umwandlung von Datenformaten geben. Selbst in Assembler genügen da weniger als 10 Zeilen.

John P. schrieb:

ich kriege die Sekunden von einer App als Hex Wert gesendet.

Beispiel: 54 sec

wird gesendet als int mit Wert 84[Dec] was einer 54[Hex] entspricht.

Wie kriege ich jetzt die 54[Hex] in eine 54[Dec] gewandelt?

Mir wird da ganz schwindelig. Welche APP? Wie sieht die Bytefolge konkret aus? Vermutlich wird BCD geschickt. 54H/84Dec ergibt "T".

Gast #7309096
Lesenswert?

michael_ schrieb:

Meine Kenntnisse in C sind rudimentär. Aber es sollten doch einfache Anweisungen zur Umwandlung von Datenformaten geben.

mit printf geht da so einiges..

Man muss aber auch unterscheiden zwischen Zahlensystemen, und Ausgabegeschichten (ASCII)/printf etc. oder Abbildungsstrategien im Rechner (BCD z.B.).

54Hex nach 54Dez geht sowieso schlecht und macht auch keinen Sinn. BCD-Zahlen haben eine ganz eigene Rechnerei. Echt was für µc-Profis.

Am sichersten ist es, wenn es von Hex nach BCD geht, erst nach Dez (durch "A" teilen..) und diese Resultate dann als BCD behandeln - und dass ist bei Intel-Asm einfach, hat halt eine eigene Unterabteilung. Aber auch nur für die Rechnerei. Bei DOS kommt die Zahl aus dem "Rechen-Register" typischerweise nach DL, und von da aus wird dann 30 draufgezählt für die Ausgabe per ASCII-Codierung. Völlig egal, ob aus dem Rechenregister für BCD-Zahlen, oder ob aus einem normalen Register. Zahl bleibt Zahl bzwl. eine 7 bleibt eine 7, eine 6 bleibt eine 6, eine 5 bleibt eine 5..

Da aber auch die Problembeschreibung / Ist/Soll vom TE oben nicht ganz durchsichtig bzw. logisch ist, denke ich mal das ist ein Teil des Problems an sich: Die Zusammenhänge des Geschehens nicht so recht durchblicken. Oft soll es ja schon helfen, das Problem zu verstehen, wenn man die Frage etwas genauer formulieren kann.

michael_ schrieb:

Das macht es auch nicht besser. Wenn man das ausgiebt kommt "J" heraus.

4A ist die Hexzahl für 74. 0111 0100 - Der ASCII-Code für 4A ist typischerweise 0011 0100 0100 0001 und hat nichts mit dem Zahlensystem zu tun, sondern nur mit der Ausgabe. 7A war der Hexwert für den ASM-Befehl JA - welcher Jump if above meinte. Ich hatte das deswegen durcheinander gebracht, ganz genau weil gewisse Dinge so merkwürdig sind: 7A, JA - 4A, J (Ja Ja..). - 4B -> K (ASCII) 4C -> L(ASCII).

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