Hex-String umwandeln (char []) nach int?

Lesezeit: 8 Minuten

Benutzeravatar von kizyle502
kizyle502

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.

  • 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

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 verwenden 0 Anstatt von 16.

    – Jens Gustedt

    14. April 2012 um 19:44 Uhr

  • Als Anmerkung strtol gibt Ihnen Typ long Das ist großartig, wenn man es mit einem sehr großen Hex zu tun hat. Verwenden strtoll für Typ long 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 erhalten unsigned int. Und selbst wenn Sie das beheben, wenn die durch die Zeichenfolge dargestellte Zahl größer als ist UINT_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

1421160cookie-checkHex-String umwandeln (char []) nach int?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy