Ich habe einen Char[] das einen Wert wie “0x1800785” enthält, aber die Funktion, der ich den Wert geben möchte, erfordert ein Int, wie kann ich das in ein Int umwandeln? Ich habe herumgesucht, aber keine Antwort finden können. Vielen Dank.
Hex-String umwandeln (char []) nach int?
kizyle502
Hast du es versucht strtol()
?
strtol – Konvertiert eine Zeichenfolge in eine lange Ganzzahl
Beispiel:
const char *hexstring = "abcdef0";
int number = (int)strtol(hexstring, NULL, 16);
Falls die Zeichenfolgendarstellung der Zahl mit a beginnt 0x
Präfix, eins muss sollte 0 als Basis verwenden:
const char *hexstring = "0xabcdef0";
int number = (int)strtol(hexstring, NULL, 0);
(Es ist auch möglich, eine explizite Basis wie 16 anzugeben, aber ich würde nicht empfehlen, Redundanz einzuführen.)
-
Wenn der Hexstring immer durch ein eingeleitet wird
"0x"
wie in der Frage angegeben, sollten Sie nur verwenden0
Anstatt von16
.– Jens Gustedt
14. April 2012 um 19:44 Uhr
-
Als Anmerkung
strtol
gibt Ihnen Typlong
Das ist großartig, wenn man es mit einem sehr großen Hex zu tun hat. Verwendenstrtoll
für Typlong long
für noch größere Hexen.– Steven Lu
12. August 2013 um 13:29 Uhr
-
Aufgefallen ist eine überraschende Diskrepanz zwischen „beginnt mit einem 0x-Präfix, man muss 0 als Basis verwenden“ und C11 §7.22.1.4 „Wenn der Wert der Basis 16 ist, dürfen die Zeichen 0x oder 0X optional der Folge von Buchstaben und Ziffern vorangestellt werden“ wie in
printf("%ld\n", strtol("0x12", 0, 16));
. Vielleicht möchten Sie dies überprüfen.– chux – Wiedereinsetzung von Monica
23. Dezember 2013 um 3:10 Uhr
-
@chux “muss” in “sollte” geändert, da es nicht obligatorisch, aber besser ist, die Funktion die Basis erkennen zu lassen (es beseitigt ein kleines bisschen Redundanz).
– Benutzer529758
23. Dezember 2013 um 9:15 Uhr
-
Technisch gesehen sollten Sie strtoul anstelle von strtol verwenden, da es in unsigned konvertiert wird, was bedeutet, dass Sie keine negativen Ausgaben von 8-stelligen Hex-Werten erhalten. Das hat mich eine ganze Weile stutzig gemacht! Sehen en.cppreference.com/w/c/string/byte/strtoul
– Joseph238
17. Juni 2016 um 17:17 Uhr
Oder wenn Sie eine eigene Implementierung haben möchten, habe ich diese schnelle Funktion als Beispiel geschrieben:
/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/
uint32_t hex2int(char *hex) {
uint32_t val = 0;
while (*hex) {
// get current character then increment
uint8_t byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
// shift 4 to make space for new digit, and add the 4 bits of the new digit
val = (val << 4) | (byte & 0xF);
}
return val;
}
-
Sehr nützlich für Plattformen mit begrenzten Ressourcen wie Mikrocontroller.
– Mubin Icyer
8. August 2018 um 13:30 Uhr
So etwas könnte nützlich sein:
char str[] = "0x1800785";
int num;
sscanf(str, "%x", &num);
printf("0x%x %i\n", num, num);
Lesen Mann sscanf
-
Dies führt zu undefiniertem Verhalten,
%x
muss die Adresse eines erhaltenunsigned int
. Und selbst wenn Sie das beheben, wenn die durch die Zeichenfolge dargestellte Zahl größer als istUINT_MAX
dann ist es wieder undefiniertes Verhalten– MM
11. Februar 2019 um 2:09 Uhr
Angenommen, Sie meinen, es ist eine Zeichenfolge, wie wäre es Strtol?
Verwenden strtol
wenn Sie libc zur Verfügung haben, wie die oberste Antwort vorschlägt. Wenn Sie jedoch benutzerdefinierte Sachen mögen oder auf einem Mikrocontroller ohne libc oder so sind, möchten Sie vielleicht eine leicht optimierte Version ohne komplexe Verzweigung.
#include <inttypes.h>
/**
* xtou64
* Take a hex string and convert it to a 64bit number (max 16 hex digits).
* The string must only contain digits and valid hex characters.
*/
uint64_t xtou64(const char *str)
{
uint64_t res = 0;
char c;
while ((c = *str++)) {
char v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8);
res = (res << 4) | (uint64_t) v;
}
return res;
}
Die Magie der Bitverschiebung läuft darauf hinaus: Verwenden Sie einfach die letzten 4 Bits, aber wenn es keine Ziffer ist, dann fügen Sie auch 9 hinzu.
-
Könnten Sie bei Gelegenheit etwas näher erläutern, wie die Zeile “v =” funktioniert? Ich habe es geschafft, Ihre Funktion für meine eigenen Zwecke wie folgt zu implementieren:
unsigned long long int hextou64(char *str) { unsigned long long int n = 0; char c, v; for (unsigned char i = 0; i < 16; i++) { c = *(str + i); v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8); n = (n << 4) | (unsigned long long int)v; } return n; }
– iamoumuamua
7. Mai 2020 um 8:02 Uhr
-
Mal sehen, ob ich das noch zusammenbekomme^^ Es ist ziemlich schwierig, denke ich.. Prämisse: ‘0’-‘9’ beginnen alle mit ‘0011????’ binär. ‘A’-‘F’ beginnen alle mit ‘0100???’ binär. Wir können diese Informationen verwenden, um Verzweigungen zu vermeiden. (c & 0xF) → nur die letzten vier Bits enthalten den Wert. Dies ist bereits der richtige Wert für ‘0’-‘9’. Im Fall von ‘A’-‘F’ müssen wir eine Dezimalzahl 9 hinzufügen, um den richtigen Wert zu erhalten. (Hex C zum Beispiel endet auf 0011. Das ist 3. Aber wir wollen 12. Deshalb müssen wir 9 hinzufügen.
(c >> 6) | ((c >> 3) & 0x8)
→ ergibt 9 im Falle eines Buchstabens oder 0 im Falle einer Dezimalzahl. ja, ziemlich hacky 🙂– Limettenrot
7. Mai 2020 um 10:39 Uhr
Eine schnelle & schmutzige Lösung:
// makes a number from two ascii hexa characters
int ahex2int(char a, char b){
a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
b = (b <= '9') ? b - '0' : (b & 0x7) + 9;
return (a << 4) + b;
}
Sie müssen sicher sein, dass Ihre Eingabe korrekt ist, keine Validierung enthalten (man könnte sagen, es ist C). Gut, dass es ziemlich kompakt ist, es funktioniert sowohl mit ‘A’ bis ‘F’ als auch mit ‘a’ bis ‘f’.
Der Ansatz beruht auf der Position von Buchstaben in der ASCII-Tabelle, schauen wir zB auf Wikipedia (https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png). Um es kurz zu machen, die Zahlen befinden sich unter den Zeichen, sodass die numerischen Zeichen (0 bis 9) einfach umgewandelt werden können, indem der Code für Null subtrahiert wird. Die alphabetischen Zeichen (A bis F) werden gelesen, indem andere Bits als die letzten drei Bits auf Null gesetzt werden (was effektiv dazu führt, dass es mit Groß- oder Kleinbuchstaben funktioniert), eins subtrahiert (weil nach der Bitmaskierung das Alphabet an Position eins beginnt) und zehn addiert werden ( da A bis F den 10. bis 15. Wert im Hexadezimalcode darstellen). Schließlich müssen wir die beiden Ziffern kombinieren, die das untere und das obere Halbbyte der codierten Zahl bilden.
Hier gehen wir mit dem gleichen Ansatz (mit geringfügigen Abweichungen):
#include <stdio.h>
// takes a null-terminated string of hexa characters and tries to
// convert it to numbers
long ahex2num(unsigned char *in){
unsigned char *pin = in; // lets use pointer to loop through the string
long out = 0; // here we accumulate the result
while(*pin != 0){
out <<= 4; // we have one more input character, so
// we shift the accumulated interim-result one order up
out += (*pin < 'A') ? *pin & 0xF : (*pin & 0x7) + 9; // add the new nibble
pin++; // go ahead
}
return out;
}
// main function will test our conversion fn
int main(void) {
unsigned char str[] = "1800785"; // no 0x prefix, please
long num;
num = ahex2num(str); // call the function
printf("Input: %s\n",str); // print input string
printf("Output: %x\n",num); // print the converted number back as hexa
printf("Check: %ld = %ld \n",num,0x1800785); // check the numeric values matches
return 0;
}
-
Könnten Sie bei Gelegenheit etwas näher erläutern, wie die Zeile “v =” funktioniert? Ich habe es geschafft, Ihre Funktion für meine eigenen Zwecke wie folgt zu implementieren:
unsigned long long int hextou64(char *str) { unsigned long long int n = 0; char c, v; for (unsigned char i = 0; i < 16; i++) { c = *(str + i); v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8); n = (n << 4) | (unsigned long long int)v; } return n; }
– iamoumuamua
7. Mai 2020 um 8:02 Uhr
-
Mal sehen, ob ich das noch zusammenbekomme^^ Es ist ziemlich schwierig, denke ich.. Prämisse: ‘0’-‘9’ beginnen alle mit ‘0011????’ binär. ‘A’-‘F’ beginnen alle mit ‘0100???’ binär. Wir können diese Informationen verwenden, um Verzweigungen zu vermeiden. (c & 0xF) → nur die letzten vier Bits enthalten den Wert. Dies ist bereits der richtige Wert für ‘0’-‘9’. Im Fall von ‘A’-‘F’ müssen wir eine Dezimalzahl 9 hinzufügen, um den richtigen Wert zu erhalten. (Hex C zum Beispiel endet auf 0011. Das ist 3. Aber wir wollen 12. Deshalb müssen wir 9 hinzufügen.
(c >> 6) | ((c >> 3) & 0x8)
→ ergibt 9 im Falle eines Buchstabens oder 0 im Falle einer Dezimalzahl. ja, ziemlich hacky 🙂– Limettenrot
7. Mai 2020 um 10:39 Uhr
Probieren Sie den folgenden Codeblock aus, er funktioniert bei mir.
char p[] = "0x820";
uint16_t intVal;
sscanf(p, "%x", &intVal);
printf("value x: %x - %d", intVal, intVal);
Ausgabe ist:
value x: 820 - 2080
mögliches Duplikat von convert string into signed int
– Bitmaske
14. April 2012 um 19:20 Uhr
Verwenden Sie strtol() mit base=16, der Rest der Verwendung ist hier: stackoverflow.com/questions/14176123/correct-usage-of-strtol
– ivan.ukr
21. Mai 2021 um 5:55 Uhr