Hex-String (char []) in int konvertieren?

81

Ich habe ein char [], das einen Wert wie "0x1800785" enthält, aber für die Funktion, der ich den Wert geben möchte, ist ein int erforderlich. Wie kann ich dies in ein int konvertieren? Ich habe mich umgesehen, kann aber keine Antwort finden. Vielen Dank.

kizyle502
quelle
1
mögliches Duplikat der Konvertierungszeichenfolge in signierte Int
Bitmaske

Antworten:

205

Hast du es versucht strtol()?

strtol - Konvertiert einen String in eine lange Ganzzahl

Beispiel:

const char *hexstring = "abcdef0";
int number = (int)strtol(hexstring, NULL, 16);

Wenn die Zeichenfolgendarstellung der Zahl mit einem 0xPräfix beginnt , muss 0 als Basis verwendet werden:

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 die Einführung von Redundanz nicht empfehlen.)

Mahendra Gunawardena
quelle
4
Wenn der Hexstring immer durch ein "0x"wie in der Frage angegeben eingeführt wird, sollten Sie einfach 0anstelle von verwenden 16.
Jens Gustedt
16
@ KelvinHu Traue cplusplus.com nicht, es ist Mist. Wenn überhaupt, gehen Sie zu cppreference.com .
1
@KelvinHu Auf dieser Site befinden sich viele technisch inkorrekte oder lose formulierte Informationen. Wenn Sie C ++ - Programmierer in der Nähe von SO sehen, raten alle davon ab, sich aus diesem Grund darauf zu verlassen.
1
@ H2CO3 Okay, ich verstehe, ich bin neu in C ++, also suche ich dies mit Google und es platziert cplusplus.com an der vordersten Position. Wirklich danke für Ihre Informationen.
Kelvin Hu
3
Als Randnotiz strtolgibt Ihnen Typ, longder großartig ist, wenn Sie mit einem sehr großen Hex arbeiten. Verwenden Sie strtollfür Typ long longfür noch größere Felder.
Steven Lu
20

Oder wenn Sie eine eigene Implementierung haben möchten, habe ich diese Schnellfunktion 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;
}
Radhoo
quelle
1
Sehr nützlich für Plattformen mit begrenzten Ressourcen wie Mikrocontroller.
Mubin Icyer
19

So etwas könnte nützlich sein:

char str[] = "0x1800785";
int num;

sscanf(str, "%x", &num);
printf("0x%x %i\n", num, num); 

Lesen Sie man sscanf

Saxi
quelle
1
Dies führt zu undefiniertem Verhalten, %xmuss die Adresse eines erhalten unsigned int. Und selbst wenn Sie das beheben, wenn die durch die Zeichenfolge dargestellte Zahl größer als UINT_MAXist, ist es wieder undefiniertes Verhalten
MM
10

Angenommen, Sie meinen, es ist eine Zeichenfolge, wie wäre es mit strtol ?

James McLaughlin
quelle
Ich hatte ursprünglich mit strtod (-> double) anstelle von strtol verlinkt. Ich denke, jemand hat es gesehen, während ich es bearbeitet habe.
James McLaughlin
Nun, das ist kein großer Fehler ... Der Compiler wandelt den Rückgabewert automatisch um, wenn er einem zugeführt wird int. +1, übrigens.
Ich glaube nicht, dass ein Double alle möglichen Werte speichern kann, die eine 32-Bit-Ganzzahl kann (weiß eigentlich jemand, ob dies wahr ist? Ich bin nicht zu 100% in der Darstellung von Gleitkommazahlen.)
James McLaughlin
4
@ JamesMcLaughlin Es kann. Ein 64-Bit-IEEE-Double hat eine Integralgenauigkeit von etwa 2 ^ 53.
Detail: "Ein 64-Bit-IEEE-Double hat eine Integralgenauigkeit von etwa 2 ^ 53." und ein Zeichenbit. So kann es mit int54_tund umgehen uint53_t.
chux
4

Verwenden strtolSie diese Option, wenn libc verfügbar ist, wie in der oberen Antwort angegeben. Wenn Sie jedoch benutzerdefinierte Inhalte mögen oder sich auf einem Mikrocontroller ohne libc oder so befinden, möchten Sie möglicherweise 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 sich um eine Nicht-Ziffer handelt, addieren Sie auch 9.

LimeRed
quelle
Wenn Sie eine Chance bekommen, können Sie etwas näher darauf eingehen, 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
Lassen Sie mich sehen, ob ich das noch zusammenbringen kann ^^ Es ist ziemlich schwierig, denke ich. Prämisse: '0' - '9' beginnen alle mit '0011 ????' in binär. 'A' - 'F' beginnen alle mit '0100 ????' in 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 Dezimalstelle 9 hinzufügen, um den korrekten Wert zu erhalten. (Hex C endet zum Beispiel mit 0011. Das ist 3. Aber wir wollen 12. Deshalb müssen wir 9 hinzufügen. (c >> 6) | ((c >> 3) & 0x8)→ ergibt 9 im Fall eines Buchstabens oder 0 im Fall einer Dezimalzahl. Ja, ziemlich hackig :)
LimeRed
3

Versuchen Sie es unter dem Codeblock, der für mich funktioniert.

char *p = "0x820";
uint16_t intVal;
sscanf(p, "%x", &intVal);

printf("value x: %x - %d", intVal, intVal);

Ausgabe ist:

value x: 820 - 2080
Grabe den Code
quelle
3

Nachdem ich eine Weile gesucht und herausgefunden habe, dass strtol ziemlich langsam ist, habe ich meine eigene Funktion codiert. Es funktioniert nur für Großbuchstaben bei Buchstaben, aber das Hinzufügen von Kleinbuchstaben ist kein Problem.

int hexToInt(PCHAR _hex, int offset = 0, int size = 6)
{
    int _result = 0;
    DWORD _resultPtr = reinterpret_cast<DWORD>(&_result);
    for(int i=0;i<size;i+=2)
    {
        int _multiplierFirstValue = 0, _addonSecondValue = 0;

        char _firstChar = _hex[offset + i];
        if(_firstChar >= 0x30 && _firstChar <= 0x39)
            _multiplierFirstValue = _firstChar - 0x30;
        else if(_firstChar >= 0x41 && _firstChar <= 0x46)
            _multiplierFirstValue = 10 + (_firstChar - 0x41);

        char _secndChar = _hex[offset + i + 1];
        if(_secndChar >= 0x30 && _secndChar <= 0x39)
            _addonSecondValue = _secndChar - 0x30;
        else if(_secndChar >= 0x41 && _secndChar <= 0x46)
            _addonSecondValue = 10 + (_secndChar - 0x41);

        *(BYTE *)(_resultPtr + (size / 2) - (i / 2) - 1) = (BYTE)(_multiplierFirstValue * 16 + _addonSecondValue);
    }
    return _result;
}

Verwendung:

char *someHex = "#CCFF00FF";
int hexDevalue = hexToInt(someHex, 1, 8);

1, weil das Hex, das wir konvertieren möchten, bei Offset 1 beginnt, und 8, weil es die Hex-Länge ist.

Speedtest (1.000.000 Anrufe):

strtol ~ 0.4400s
hexToInt ~ 0.1100s
mexikanoZ
quelle
2

Eine schnelle und 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 basiert auf der Position der Alphabetzeichen in der ASCII-Tabelle. Schauen wir uns beispielsweise Wikipedia an ( https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png ). Kurz gesagt, die Zahlen befinden sich unter den Zeichen, sodass die numerischen Zeichen (0 bis 9) leicht konvertiert werden können, indem der Code für Null subtrahiert wird. Die alphabetischen Zeichen (A bis F) werden gelesen, indem andere als die letzten drei Bits auf Null gesetzt werden (was effektiv dazu führt, dass entweder Groß- oder Kleinbuchstaben verwendet werden), eins subtrahiert wird (da das Alphabet nach der Bitmaskierung an Position eins beginnt) und zehn addiert werden ( weil A bis F den 10. bis 15. Wert im Hexadezimalcode darstellen). Schließlich müssen wir die beiden Ziffern kombinieren, die das untere und 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;
}
Simon
quelle
Nachdem ich die Antwort gepostet hatte, fand ich heraus, dass ich den Beitrag von @LimeRed verpasst habe, der sehr süß ist
Simon
1

Dies ist eine Funktion zum direkten Konvertieren von hexadezimalem char-Array in eine Ganzzahl, für die keine zusätzliche Bibliothek erforderlich ist:

int hexadecimal2int(char *hdec) {
    int finalval = 0;
    while (*hdec) {
        
        int onebyte = *hdec++; 
        
        if (onebyte >= '0' && onebyte <= '9'){onebyte = onebyte - '0';}
        else if (onebyte >= 'a' && onebyte <='f') {onebyte = onebyte - 'a' + 10;}
        else if (onebyte >= 'A' && onebyte <='F') {onebyte = onebyte - 'A' + 10;}  
        
        finalval = (finalval << 4) | (onebyte & 0xF);
    }
    finalval = finalval - 524288;
    return finalval;
}
Vaibhav VK
quelle
0

Ich habe eine Bibliothek erstellt, um eine Hexadezimal- / Dezimal-Konvertierung ohne Verwendung von durchzuführen stdio.h. Sehr einfach zu bedienen:

unsigned hexdec (const char *hex, const int s_hex);

Initialisieren Sie vor der ersten Konvertierung das für die Konvertierung verwendete Array mit:

void init_hexdec ();

Hier der Link auf Github: https://github.com/kevmuret/libhex/

kevmuret
quelle
0

Ich habe eine ähnliche Sache gemacht, denke, es könnte dir helfen, dass es tatsächlich für mich funktioniert

int main(){ int co[8],i;char ch[8];printf("please enter the string:");scanf("%s",ch);for(i=0;i<=7;i++){if((ch[i]>='A')&&(ch[i]<='F')){co[i]=(unsigned int)ch[i]-'A'+10;}else if((ch[i]>='0')&&(ch[i]<='9')){co[i]=(unsigned int)ch[i]-'0'+0;}}

hier habe ich nur eine Zeichenfolge von 8 Zeichen genommen. Wenn du willst, dass du eine ähnliche Logik für 'a' zu 'f' hinzufügen kannst, um ihre äquivalenten Hex-Werte anzugeben, habe ich das nicht getan, weil ich es nicht gebraucht habe.

Sairam Singh
quelle
-1

Verwenden Sie xtoi (stdlib.h). Die Zeichenfolge hat "0x" als erste zwei Indizes, also trimmen Sie val [0] und val [1] aus, indem Sie xtoi & val [2] senden.

xtoi( &val[2] );

Burstfulovic
quelle
xtoiist keine Standardfunktion
MM
-5

Ich weiß, dass dies wirklich alt ist, aber ich denke, die Lösungen sahen zu kompliziert aus. Versuchen Sie dies in VB:

Public Function HexToInt(sHEX as String) as long
Dim iLen as Integer
Dim i as Integer 
Dim SumValue as Long 
Dim iVal as long
Dim AscVal as long

    iLen = Len(sHEX)
    For i = 1 to Len(sHEX)
      AscVal = Asc(UCase(Mid$(sHEX, i,  1)))
      If AscVal >= 48 And AscVal  <= 57 Then
        iVal  = AscVal - 48
      ElseIf AscVal >= 65 And AscVal <= 70 Then
        iVal = AscVal - 55
      End If 
      SumValue = SumValue + iVal * 16 ^ (iLen- i)
    Next i 
    HexToInt  = SumValue
End Function 
CHEWBAKKEE
quelle