Mam znak char [], który zawiera wartość, taką jak „0x1800785”, ale funkcja, której chcę nadać wartość, wymaga int, jak mogę przekonwertować to na int? Szukałem w okolicy, ale nie mogę znaleźć odpowiedzi. Dzięki.
Jeśli ciąg szesnastkowy jest zawsze wprowadzany przez a, "0x"jak podano w pytaniu, powinieneś po prostu użyć 0zamiast 16.
Jens Gustedt,
16
@KelvinHu Nie ufaj cplusplus.com, to bzdura. Jeśli tak, przejdź do cppreference.com .
1
@KelvinHu Wiele technicznie niepoprawnych lub luźno sformułowanych informacji znajduje się w tej witrynie, a jeśli zobaczysz programistów C ++ wokół SO, wszyscy zniechęcą do polegania na niej z tego powodu.
1
@ H2CO3 Okay, widzę, jestem nowy w C ++, więc wyszukuję to w google i umieszczam cplusplus.com na samym początku. Naprawdę dziękuję za twoją informację.
Kelvin Hu
3
Na marginesie strtolpodaje typ, longktóry świetnie sprawdza się w przypadku bardzo dużego heksa. Użyj strtolldo pisania long longdla jeszcze większych heksów.
Steven Lu
20
Lub jeśli chcesz mieć własną implementację, napisałem tę szybką funkcję jako przykład:
/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/uint32_thex2int(char *hex){
uint32_t val = 0;
while (*hex) {
// get current character then incrementuint8_t byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexesif (byte >= '0' && byte <= '9') byte = byte - '0';
elseif (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
elseif (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;
}
Powoduje to niezdefiniowane zachowanie, %xmusi otrzymać adres pliku unsigned int. A nawet jeśli to naprawisz, jeśli liczba reprezentowana przez ciąg jest większa niż UINT_MAX, oznacza to ponownie niezdefiniowane zachowanie
MM
10
Zakładając, że masz na myśli ciąg, a co powiesz na strtol ?
Początkowo łączyłem się ze strtod (-> double) zamiast strtol. Chyba ktoś to widział, kiedy redagowałem.
James McLaughlin,
Cóż, to nie jest duży błąd ... kompilator automatycznie rzuca wartość zwracaną, jeśli zostanie przekazana do pliku int. +1, przy okazji.
Nie sądzę podwójne może przechowywać wszystkie możliwe wartości 32-bitowej liczby całkowitej puszkę (faktycznie, czy ktoś wie, czy jest to prawda, nie jestem 100% na liczbę zmiennoprzecinkową reprezentacji?).
James McLaughlin
4
@JamesMcLaughlin To może. 64-bitowy podwójny IEEE ma całkowitą dokładność do około 2 ^ 53.
Szczegóły: „64-bitowy podwójny IEEE ma całkowitą dokładność do około 2 ^ 53”. i trochę znak. Więc może obsłużyć int54_ti uint53_t.
chux - Przywróć Monikę
5
Użyj, strtoljeśli masz dostępną bibliotekę libc, jak sugeruje najlepsza odpowiedź. Jeśli jednak lubisz niestandardowe rzeczy lub korzystasz z mikrokontrolera bez biblioteki libc lub czegoś podobnego, możesz potrzebować nieco zoptymalizowanej wersji bez skomplikowanych rozgałęzień.
#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_txtou64(constchar *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;
}
Magia przesuwania bitów sprowadza się do: Po prostu użyj ostatnich 4 bitów, ale jeśli nie jest to cyfra, dodaj także 9.
Jeśli będziesz miał okazję, mógłbyś wyjaśnić trochę więcej na temat działania linii „v =”? Udało mi się zaimplementować twoją funkcję do własnych celów w następujący sposób: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
Zobaczmy, czy uda mi się to jeszcze połączyć ^^ Wydaje mi się, że jest to dość trudne .. Przesłanka: „0” - „9” wszystkie zaczynają się od „0011 ????” binarnie. „A” - „F” zaczynają się od „0100 ????” binarnie. Możemy wykorzystać te informacje, aby uniknąć rozgałęzień. (c & 0xF) → tylko ostatnie cztery bity zawierają wartość. To jest już poprawna wartość dla „0” - „9”. W przypadku „A” - „F” musimy dodać 9 dziesiętne, aby uzyskać prawidłową wartość. (Na przykład Hex C kończy się na 0011. Co jest 3. Ale chcemy 12. Dlatego musimy dodać 9. (c >> 6) | ((c >> 3) & 0x8)→ daje w wyniku 9 w przypadku litery lub 0 w przypadku ułamka dziesiętnego. Tak, całkiem
Tak więc po chwili wyszukiwania i stwierdzeniu, że strtol jest dość powolny, zakodowałem własną funkcję. Działa tylko w przypadku wielkich liter, ale dodanie funkcji małych liter nie stanowi problemu.
// makes a number from two ascii hexa charactersintahex2int(char a, char b){
a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
b = (b <= '9') ? b - '0' : (b & 0x7) + 9;
return (a << 4) + b;
}
Musisz mieć pewność, że wprowadzone dane są poprawne, bez weryfikacji (można powiedzieć, że to C). Dobrze, że jest dość kompaktowy, działa zarówno z „A” do „F”, jak i „a” do „f”.
Podejście opiera się na pozycji znaków alfabetu w tabeli ASCII, zajrzyjmy np. Do Wikipedii ( https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png ). Krótko mówiąc, liczby znajdują się pod znakami, więc znaki numeryczne (od 0 do 9) można łatwo przekonwertować, odejmując kod na zero. Znaki alfabetu (od A do F) są odczytywane przez zerowanie inne niż ostatnie trzy bity (efektywnie dzięki czemu działa z dużą lub małą literą), odejmowanie jednego (ponieważ po maskowaniu bitów, alfabet zaczyna się na pozycji pierwszej) i dodawanie dziesięciu ( ponieważ od A do F reprezentują od 10 do 15 wartości w kodzie szesnastkowym). Na koniec musimy połączyć dwie cyfry, które tworzą dolną i górną część zakodowanej liczby.
Tutaj idziemy z tym samym podejściem (z niewielkimi zmianami):
#include<stdio.h>// takes a null-terminated string of hexa characters and tries to // convert it to numberslongahex2num(unsignedchar *in){
unsignedchar *pin = in; // lets use pointer to loop through the stringlong out = 0; // here we accumulate the resultwhile(*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 fnintmain(void){
unsignedchar str[] = "1800785"; // no 0x prefix, pleaselong num;
num = ahex2num(str); // call the functionprintf("Input: %s\n",str); // print input stringprintf("Output: %x\n",num); // print the converted number back as hexaprintf("Check: %ld = %ld \n",num,0x1800785); // check the numeric values matchesreturn0;
}
Po opublikowaniu odpowiedzi dowiedziałem się, że przegapiłem post @LimeRed, który jest bardzo uroczy
Simon
1
Jest to funkcja umożliwiająca bezpośrednią konwersję szesnastkowej tablicy znaków zawierającej znaki na liczbę całkowitą, która nie wymaga dodatkowej biblioteki:
Zrobiłem podobną rzecz, myślę, że może ci to pomóc, że faktycznie działa dla mnie
intmain(){ 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]=(unsignedint)ch[i]-'A'+10;}elseif((ch[i]>='0')&&(ch[i]<='9')){co[i]=(unsignedint)ch[i]-'0'+0;}}
tutaj wziąłem tylko ciąg 8 znaków. jeśli chcesz, możesz dodać podobną logikę dla „a” do „f”, aby podać ich równoważne wartości szesnastkowe, nie zrobiłem tego, ponieważ nie potrzebowałem tego.
Wiem, że to jest naprawdę stare, ale myślę, że rozwiązania wyglądały na zbyt skomplikowane. Spróbuj tego w 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
Odpowiedzi:
Czy próbowałeś
strtol()
?strtol - konwertuje ciąg znaków na długą liczbę całkowitą
Przykład:
const char *hexstring = "abcdef0"; int number = (int)strtol(hexstring, NULL, 16);
W przypadku znaków reprezentujący numer zaczyna się od
0x
prefiksu, jedenmusipowinni stosować 0 jako podstawy:const char *hexstring = "0xabcdef0"; int number = (int)strtol(hexstring, NULL, 0);
(Równie dobrze można określić jawną podstawę, taką jak 16, ale nie polecałbym wprowadzania nadmiarowości).
źródło
"0x"
jak podano w pytaniu, powinieneś po prostu użyć0
zamiast16
.strtol
podaje typ,long
który świetnie sprawdza się w przypadku bardzo dużego heksa. Użyjstrtoll
do pisanialong long
dla jeszcze większych heksów.Lub jeśli chcesz mieć własną implementację, napisałem tę szybką funkcję jako przykład:
/** * 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; }
źródło
Coś takiego może się przydać:
char str[] = "0x1800785"; int num; sscanf(str, "%x", &num); printf("0x%x %i\n", num, num);
Przeczytaj man sscanf
źródło
%x
musi otrzymać adres plikuunsigned int
. A nawet jeśli to naprawisz, jeśli liczba reprezentowana przez ciąg jest większa niżUINT_MAX
, oznacza to ponownie niezdefiniowane zachowanieZakładając, że masz na myśli ciąg, a co powiesz na strtol ?
źródło
int
. +1, przy okazji.int54_t
iuint53_t
.Użyj,
strtol
jeśli masz dostępną bibliotekę libc, jak sugeruje najlepsza odpowiedź. Jeśli jednak lubisz niestandardowe rzeczy lub korzystasz z mikrokontrolera bez biblioteki libc lub czegoś podobnego, możesz potrzebować nieco zoptymalizowanej wersji bez skomplikowanych rozgałęzień.#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; }
Magia przesuwania bitów sprowadza się do: Po prostu użyj ostatnich 4 bitów, ale jeśli nie jest to cyfra, dodaj także 9.
źródło
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; }
(c >> 6) | ((c >> 3) & 0x8)
→ daje w wyniku 9 w przypadku litery lub 0 w przypadku ułamka dziesiętnego. Tak, całkiemWypróbuj poniższy blok kodu, działa dla mnie.
char *p = "0x820"; uint16_t intVal; sscanf(p, "%x", &intVal); printf("value x: %x - %d", intVal, intVal);
Wynik to:
value x: 820 - 2080
źródło
Tak więc po chwili wyszukiwania i stwierdzeniu, że strtol jest dość powolny, zakodowałem własną funkcję. Działa tylko w przypadku wielkich liter, ale dodanie funkcji małych liter nie stanowi problemu.
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; }
Stosowanie:
char *someHex = "#CCFF00FF"; int hexDevalue = hexToInt(someHex, 1, 8);
1, ponieważ hex, który chcemy przekonwertować, zaczyna się od przesunięcia 1, a 8, ponieważ jest to długość szesnastkowa.
Speedtest (1.000.000 połączeń):
strtol ~ 0.4400s hexToInt ~ 0.1100s
źródło
Jedno szybkie i brudne rozwiązanie:
// 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; }
Musisz mieć pewność, że wprowadzone dane są poprawne, bez weryfikacji (można powiedzieć, że to C). Dobrze, że jest dość kompaktowy, działa zarówno z „A” do „F”, jak i „a” do „f”.
Podejście opiera się na pozycji znaków alfabetu w tabeli ASCII, zajrzyjmy np. Do Wikipedii ( https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png ). Krótko mówiąc, liczby znajdują się pod znakami, więc znaki numeryczne (od 0 do 9) można łatwo przekonwertować, odejmując kod na zero. Znaki alfabetu (od A do F) są odczytywane przez zerowanie inne niż ostatnie trzy bity (efektywnie dzięki czemu działa z dużą lub małą literą), odejmowanie jednego (ponieważ po maskowaniu bitów, alfabet zaczyna się na pozycji pierwszej) i dodawanie dziesięciu ( ponieważ od A do F reprezentują od 10 do 15 wartości w kodzie szesnastkowym). Na koniec musimy połączyć dwie cyfry, które tworzą dolną i górną część zakodowanej liczby.
Tutaj idziemy z tym samym podejściem (z niewielkimi zmianami):
#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; }
źródło
Jest to funkcja umożliwiająca bezpośrednią konwersję szesnastkowej tablicy znaków zawierającej znaki na liczbę całkowitą, która nie wymaga dodatkowej biblioteki:
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; }
źródło
Zrobiłem librairy, aby dokonać konwersji szesnastkowej / dziesiętnej bez użycia
stdio.h
. Bardzo prosty w użyciu:unsigned hexdec (const char *hex, const int s_hex);
Przed pierwszą konwersją zainicjuj tablicę używaną do konwersji za pomocą:
void init_hexdec ();
Tutaj link na github: https://github.com/kevmuret/libhex/
źródło
Zrobiłem podobną rzecz, myślę, że może ci to pomóc, że faktycznie działa dla mnie
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;}}
tutaj wziąłem tylko ciąg 8 znaków. jeśli chcesz, możesz dodać podobną logikę dla „a” do „f”, aby podać ich równoważne wartości szesnastkowe, nie zrobiłem tego, ponieważ nie potrzebowałem tego.
źródło
Wiem, że to jest naprawdę stare, ale myślę, że rozwiązania wyglądały na zbyt skomplikowane. Spróbuj tego w 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
źródło