Преобразовать шестнадцатеричную строку (char []) в int?
82
У меня есть char [], который содержит такое значение, как "0x1800785", но функция, которой я хочу присвоить значение, требует int, как я могу преобразовать это в int? Я поискал, но не нашел ответа. Благодарю.
Если шестнадцатеричная строка всегда вводится "0x"как указано в вопросе, вы должны просто использовать 0вместо 16.
Йенс Густедт
16
@KelvinHu Не верь cplusplus.com, это чушь. Если есть, перейдите на cppreference.com .
1
@KelvinHu На этом сайте много технически некорректной или некорректно сформулированной информации, и если вы встретите программистов на C ++ вокруг SO, они все отговорят полагаться на нее по этой причине.
1
@ H2CO3 Хорошо, понятно, я новичок в C ++, поэтому я ищу это в Google, и он помещает cplusplus.com на первое место. Действительно спасибо за вашу информацию.
Кельвин Ху
3
В качестве побочного примечания strtolдает вам тип, longкоторый отлично подходит при работе с очень большим шестиугольником. Используйте strtollдля шрифта long longдля еще более крупных гексов.
Стивен Лу,
20
Или, если вы хотите иметь свою собственную реализацию, я написал эту быструю функцию в качестве примера:
/**
* 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;
}
Это вызывает неопределенное поведение, %xнеобходимо получить адрес unsigned int. И даже если вы исправите это, если число, представленное строкой, больше, чем, UINT_MAXто это снова неопределенное поведение
ММ
10
Предполагая, что вы имеете в виду строку, как насчет strtol ?
Изначально я связался с strtod (-> double) вместо strtol. Думаю, кто-то видел это, пока я редактировал.
Джеймс Маклафлин,
Что ж, это небольшая ошибка ... компилятор автоматически приводит возвращаемое значение, если оно передано в файл int. +1, кстати.
Я не думаю, что double может хранить все возможные значения, которые может хранить 32-битное целое число (на самом деле, кто-нибудь знает, правда ли это? Я не на 100% в представлении чисел с плавающей запятой.)
Джеймс Маклафлин,
4
@JamesMcLaughlin Может. 64-битный IEEE double имеет интегральную точность примерно до 2 ^ 53.
Подробно: «64-битный IEEE double имеет целочисленную точность примерно 2 ^ 53». и бит знака. Так что может справиться int54_tи uint53_t.
chux
5
Используйте, strtolесли у вас есть libc, как предлагает верхний ответ. Однако, если вам нравятся нестандартные вещи или вы используете микроконтроллер без libc или около того, вам может потребоваться слегка оптимизированная версия без сложного ветвления.
#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;
}
Магия битового сдвига сводится к следующему: просто используйте последние 4 бита, но если это не цифра, тогда также добавьте 9.
Если у вас будет возможность, не могли бы вы подробнее рассказать о том, как работает строка "v ="? Мне удалось реализовать вашу функцию для моих целей следующим образом: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
Дай-ка я посмотрю, смогу ли я собрать это вместе ^^ Думаю, это довольно сложно .. Предпосылка: «0» - «9» начинаются с «0011 ????» в двоичном формате. «A» - «F» начинаются с «0100 ????» в двоичном формате. Мы можем использовать эту информацию, чтобы избежать ветвления. (c & 0xF) → только последние четыре бита содержат значение. Это уже правильное значение для «0» - «9». В случае «A» - «F» мы должны добавить десятичную дробь 9, чтобы получить правильное значение. (Hex C, например, заканчивается на 0011. Это 3. Но мы хотим 12. Поэтому мы должны добавить 9. (c >> 6) | ((c >> 3) & 0x8)→ оценивается как 9 в случае буквы или 0 в случае десятичной дроби. Да, довольно хакерский :)
Итак, после некоторого времени поиска и обнаружения того, что strtol довольно медленный, я закодировал свою собственную функцию. Он работает только для прописных букв, но добавление строчных букв не проблема.
// 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;
}
Вы должны быть уверены, что ваш ввод правильный, без проверки (можно сказать, что это C). Хорошо, что он довольно компактен, работает как с буквами от «А» до «F», так и от «а» до «f».
Подход основан на положении букв алфавита в таблице ASCII, давайте заглянем, например, в Википедию ( https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png) ). Короче говоря, цифры находятся под символами, поэтому числовые символы (от 0 до 9) легко преобразовываются путем вычитания кода для нуля. Буквенные символы (от A до F) считываются путем обнуления, отличного от последних трех битов (эффективно заставляя его работать с верхним или нижним регистром), вычитания единицы (поскольку после битовой маскировки алфавит начинается с первой позиции) и добавления десяти ( потому что от A до F представляют собой значения с 10-го по 15-е в шестнадцатеричном коде). Наконец, нам нужно объединить две цифры, которые образуют нижний и верхний полубайт закодированного числа.
Здесь мы используем тот же подход (с небольшими вариациями):
#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;
}
Отправив ответ, я обнаружил, что пропустил сообщение @LimeRed, что очень мило
Саймон
1
Это функция для прямого преобразования шестнадцатеричного числа, содержащего массив символов, в целое число, которое не требует дополнительной библиотеки:
Я сделал то же самое, думаю, это может помочь тебе, это действительно работает для меня
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;}}
здесь я взял только строку из 8 символов. Если вы хотите, вы можете добавить аналогичную логику для 'a' в 'f', чтобы дать их эквивалентные шестнадцатеричные значения, я не сделал этого, потому что мне это не нужно.
Я знаю, что это действительно стар, но я думаю, что решения выглядели слишком сложными. Попробуйте это в 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
Ответы:
Вы пробовали
strtol()
?strtol - преобразовать строку в длинное целое число
Пример:
const char *hexstring = "abcdef0"; int number = (int)strtol(hexstring, NULL, 16);
В случае, если строковое представление числа начинается с
0x
префикса,необходимоиспользовать 0 в качестве основы:const char *hexstring = "0xabcdef0"; int number = (int)strtol(hexstring, NULL, 0);
(Также можно указать явную базу, например 16, но я бы не рекомендовал вводить избыточность.)
источник
"0x"
как указано в вопросе, вы должны просто использовать0
вместо16
.strtol
дает вам тип,long
который отлично подходит при работе с очень большим шестиугольником. Используйтеstrtoll
для шрифтаlong long
для еще более крупных гексов.Или, если вы хотите иметь свою собственную реализацию, я написал эту быструю функцию в качестве примера:
/** * 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; }
источник
Что-то вроде этого может быть полезно:
char str[] = "0x1800785"; int num; sscanf(str, "%x", &num); printf("0x%x %i\n", num, num);
Читать man sscanf
источник
%x
необходимо получить адресunsigned int
. И даже если вы исправите это, если число, представленное строкой, больше, чем,UINT_MAX
то это снова неопределенное поведениеПредполагая, что вы имеете в виду строку, как насчет strtol ?
источник
int
. +1, кстати.int54_t
иuint53_t
.Используйте,
strtol
если у вас есть libc, как предлагает верхний ответ. Однако, если вам нравятся нестандартные вещи или вы используете микроконтроллер без libc или около того, вам может потребоваться слегка оптимизированная версия без сложного ветвления.#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; }
Магия битового сдвига сводится к следующему: просто используйте последние 4 бита, но если это не цифра, тогда также добавьте 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)
→ оценивается как 9 в случае буквы или 0 в случае десятичной дроби. Да, довольно хакерский :)Попробуйте ниже блок кода, он работает для меня.
char *p = "0x820"; uint16_t intVal; sscanf(p, "%x", &intVal); printf("value x: %x - %d", intVal, intVal);
Выход:
value x: 820 - 2080
источник
Итак, после некоторого времени поиска и обнаружения того, что strtol довольно медленный, я закодировал свою собственную функцию. Он работает только для прописных букв, но добавление строчных букв не проблема.
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; }
Применение:
char *someHex = "#CCFF00FF"; int hexDevalue = hexToInt(someHex, 1, 8);
1, потому что шестнадцатеричный код, который мы хотим преобразовать, начинается со смещения 1, и 8, потому что это шестнадцатеричная длина.
Speedtest (1.000.000 звонков):
strtol ~ 0.4400s hexToInt ~ 0.1100s
источник
Одно быстрое и грязное решение:
// 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; }
Вы должны быть уверены, что ваш ввод правильный, без проверки (можно сказать, что это C). Хорошо, что он довольно компактен, работает как с буквами от «А» до «F», так и от «а» до «f».
Подход основан на положении букв алфавита в таблице ASCII, давайте заглянем, например, в Википедию ( https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png) ). Короче говоря, цифры находятся под символами, поэтому числовые символы (от 0 до 9) легко преобразовываются путем вычитания кода для нуля. Буквенные символы (от A до F) считываются путем обнуления, отличного от последних трех битов (эффективно заставляя его работать с верхним или нижним регистром), вычитания единицы (поскольку после битовой маскировки алфавит начинается с первой позиции) и добавления десяти ( потому что от A до F представляют собой значения с 10-го по 15-е в шестнадцатеричном коде). Наконец, нам нужно объединить две цифры, которые образуют нижний и верхний полубайт закодированного числа.
Здесь мы используем тот же подход (с небольшими вариациями):
#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; }
источник
Это функция для прямого преобразования шестнадцатеричного числа, содержащего массив символов, в целое число, которое не требует дополнительной библиотеки:
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; }
источник
Я сделал librairy для преобразования шестнадцатеричного / десятичного числа без использования
stdio.h
. Очень просто использовать:unsigned hexdec (const char *hex, const int s_hex);
Перед первым преобразованием инициализируйте массив, используемый для преобразования:
void init_hexdec ();
Вот ссылка на github: https://github.com/kevmuret/libhex/
источник
Я сделал то же самое, думаю, это может помочь тебе, это действительно работает для меня
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;}}
здесь я взял только строку из 8 символов. Если вы хотите, вы можете добавить аналогичную логику для 'a' в 'f', чтобы дать их эквивалентные шестнадцатеричные значения, я не сделал этого, потому что мне это не нужно.
источник
Я знаю, что это действительно стар, но я думаю, что решения выглядели слишком сложными. Попробуйте это в 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
источник