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.
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.
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, jeden musi powinni 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).
"0x"
jak podano w pytaniu, powinieneś po prostu użyć 0
zamiast 16
.
strtol
podaje typ, long
który świetnie sprawdza się w przypadku bardzo dużego heksa. Użyj strtoll
do pisania long 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;
}
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
%x
musi 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
int
. +1, przy okazji.
int54_t
i uint53_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.
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ł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.
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
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;
}
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;
}
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/
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.
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