C++ преобразовать шестнадцатеричную строку в целое число со знаком
Я хочу преобразовать шестнадцатеричную строку в 32-битное целое число со знаком в C++.
Так, например, у меня есть шестнадцатеричная строка "fffefffe". Двоичное представление этого является 11111111111111101111111111111110. Целочисленное представление со знаком этого: -65538.
Как мне сделать это преобразование в C++? Это также должно работать для неотрицательных чисел. Например, шестнадцатеричная строка "0000000A", это 00000000000000000000000000001010 в двоичном формате и 10 в десятичном виде.
11 ответов
Использование std::stringstream
unsigned int x;
std::stringstream ss;
ss << std::hex << "fffefffe";
ss >> x;
следующий пример производит -65538
как результат:
#include <sstream>
#include <iostream>
int main() {
unsigned int x;
std::stringstream ss;
ss << std::hex << "fffefffe";
ss >> x;
// output it as a signed type
std::cout << static_cast<int>(x) << std::endl;
}
В новом стандарте C++11 есть несколько новых служебных функций, которые вы можете использовать! в частности, существует семейство функций "строка в число" ( http://en.cppreference.com/w/cpp/string/basic_string/stol и http://en.cppreference.com/w/cpp/string/basic_string/stoul). По сути, это тонкие обертки вокруг функций преобразования строк в числа в Си, но они знают, как обращаться с std::string
Итак, самый простой ответ для более нового кода, вероятно, будет выглядеть так:
std::string s = "0xfffefffe";
unsigned int x = std::stoul(s, nullptr, 16);
ПРИМЕЧАНИЕ. Ниже приведен мой первоначальный ответ, который, как говорит редакция, не является полным ответом. Для функционального решения вставьте код над строкой:-).
Похоже, что с lexical_cast<>
определено, чтобы иметь семантику преобразования потока. К сожалению, потоки не понимают нотацию "0x". Так что оба boost::lexical_cast
и моя рука катится не очень хорошо с шестнадцатеричными строками. Вышеупомянутое решение, которое вручную устанавливает входной поток в шестнадцатеричный формат, прекрасно с этим справится
У Boost есть кое-что для этого, а также есть хорошие возможности проверки ошибок. Вы можете использовать это так:
try {
unsigned int x = lexical_cast<int>("0x0badc0de");
} catch(bad_lexical_cast &) {
// whatever you want to do...
}
Если вы не хотите использовать boost, вот облегченная версия лексического приведения, которая не проверяет ошибки:
template<typename T2, typename T1>
inline T2 lexical_cast(const T1 &in) {
T2 out;
std::stringstream ss;
ss << in;
ss >> out;
return out;
}
который вы можете использовать так:
// though this needs the 0x prefix so it knows it is hex
unsigned int x = lexical_cast<unsigned int>("0xdeadbeef");
Для метода, который работает с C и C++, вы можете рассмотреть возможность использования стандартной библиотечной функции strtol().
#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
string s = "abcd";
char * p;
long n = strtol( s.c_str(), & p, 16 );
if ( * p != 0 ) { //my bad edit was here
cout << "not a number" << endl;
}
else {
cout << n << endl;
}
}
Энди Бьюкенен, в том, что касается C++, мне понравился твой, но у меня есть несколько модов:
template <typename ElemT>
struct HexTo {
ElemT value;
operator ElemT() const {return value;}
friend std::istream& operator>>(std::istream& in, HexTo& out) {
in >> std::hex >> out.value;
return in;
}
};
Используется как
uint32_t value = boost::lexical_cast<HexTo<uint32_t> >("0x2a");
Таким образом, вам не нужен один impl для типа int.
Рабочий пример с strtoul
будет:
#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
string s = "fffefffe";
char * p;
long n = strtoul( s.c_str(), & p, 16 );
if ( * p != 0 ) {
cout << "not a number" << endl;
} else {
cout << n << endl;
}
}
strtol
новообращенные string
в long
, На моем компьютере numeric_limits<long>::max()
дает 0x7fffffff
, Очевидно, что 0xfffefffe
больше, чем 0x7fffffff
, Так strtol
возвращается MAX_LONG
вместо разыскиваемой стоимости. strtoul
новообращенные string
в unsigned long
поэтому в этом случае переполнения нет.
В порядке, strtol
рассматривает входную строку не как 32-разрядное целое число со знаком перед преобразованием. Смешной образец с strtol
:
#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
string s = "-0x10002";
char * p;
long n = strtol( s.c_str(), & p, 16 );
if ( * p != 0 ) {
cout << "not a number" << endl;
} else {
cout << n << endl;
}
}
Код выше печатает -65538
в консоли.
Вот простой и рабочий метод, который я нашел в другом месте:
string hexString = "7FF";
int hexNumber;
sscanf(hexString.c_str(), "%x", &hexNumber);
Обратите внимание, что вы можете предпочесть использовать беззнаковое длинное целое / длинное целое, чтобы получить значение. Еще одно замечание: функция c_str() просто конвертирует std::string в const char* .
Так что, если у вас есть готовый const char *, просто используйте это имя переменной напрямую, как показано ниже [Я также показываю использование переменной без знака long для большего шестнадцатеричного числа. Не путайте это со случаем наличия const char * вместо string]:
const char *hexString = "7FFEA5"; //Just to show the conversion of a bigger hex number
unsigned long hexNumber; //In case your hex number is going to be sufficiently big.
sscanf(hexString, "%x", &hexNumber);
Это прекрасно работает (при условии, что вы используете соответствующие типы данных в соответствии с вашими потребностями).
У меня была та же проблема сегодня, вот как я решил ее, чтобы я мог сохранить lexical_cast<>
typedef unsigned int uint32;
typedef signed int int32;
class uint32_from_hex // For use with boost::lexical_cast
{
uint32 value;
public:
operator uint32() const { return value; }
friend std::istream& operator>>( std::istream& in, uint32_from_hex& outValue )
{
in >> std::hex >> outValue.value;
}
};
class int32_from_hex // For use with boost::lexical_cast
{
uint32 value;
public:
operator int32() const { return static_cast<int32>( value ); }
friend std::istream& operator>>( std::istream& in, int32_from_hex& outValue )
{
in >> std::hex >> outvalue.value;
}
};
uint32 material0 = lexical_cast<uint32_from_hex>( "0x4ad" );
uint32 material1 = lexical_cast<uint32_from_hex>( "4ad" );
uint32 material2 = lexical_cast<uint32>( "1197" );
int32 materialX = lexical_cast<int32_from_hex>( "0xfffefffe" );
int32 materialY = lexical_cast<int32_from_hex>( "fffefffe" );
// etc...
(Нашел эту страницу, когда искал менее удачный способ:-)
Ура, А.
Просто используйте, например, stoi/stol/stoll:
std::cout << std::stol("fffefffe", nullptr, 16) << std::endl;
вывод: 4294901758
Попробуй это. Это решение немного рискованно. Чеков нет. Строка должна иметь только шестнадцатеричные значения, а длина строки должна соответствовать размеру возвращаемого типа. Но нет необходимости в дополнительных заголовках.
char hextob(char ch)
{
if (ch >= '0' && ch <= '9') return ch - '0';
if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
return 0;
}
template<typename T>
T hextot(char* hex)
{
T value = 0;
for (size_t i = 0; i < sizeof(T)*2; ++i)
value |= hextob(hex[i]) << (8*sizeof(T)-4*(i+1));
return value;
};
Применение:
int main()
{
char str[4] = {'f','f','f','f'};
std::cout << hextot<int16_t>(str) << "\n";
}
Примечание: длина строки должна делиться на 2
Это сработало для меня:
string string_test = "80123456";
unsigned long x;
signed long val;
std::stringstream ss;
ss << std::hex << string_test;
ss >> x;
// ss >> val; // if I try this val = 0
val = (signed long)x; // However, if I cast the unsigned result I get val = 0x80123456
Для тех, кто хочет преобразовать числовую базу для беззнаковых чисел, довольно тривиально выполнить себя как на C / C++ с минимальной зависимостью (только оператор, не предоставляемый самим языком,
pow()
функция).
С математической точки зрения положительное порядковое число d в базе b с числом цифр n можно преобразовать в основание 10, используя:
Пример: преобразование числа с основанием 16
00f
выглядит как:
= 0*16^2 + 0*16^1 + 16*16^0 = 15
Пример C / C++:
#include <math.h>
unsigned int to_base10(char *d_str, int len, int base)
{
if (len < 1) {
return 0;
}
char d = d_str[0];
// chars 0-9 = 48-57, chars a-f = 97-102
int val = (d > 57) ? d - ('a' - 10) : d - '0';
int result = val * pow(base, (len - 1));
d_str++; // increment pointer
return result + to_base10(d_str, len - 1, base);
}
int main(int argc, char const *argv[])
{
char n[] = "00f"; // base 16 number of len = 3
printf("%d\n", to_base10(n, 3, 16));
}
Другой метод
using namespace System;
template <typename NUM>
NUM hexstr2num(String^ h)
{
NUM v=0;
String^ k=L"0123456789ABCDEF";
short l=h->Length;
char off;
h=h->ToUpper();
if(h->Substring(0,1)!=L"H")
{if(h->Substring(0,2)==L"0X") off=2;}
else
{off=1;}
if(!off) throw;
char dx=0;
for(int i=l;i>off;i--)
{
if((dx=k->IndexOf(h->Substring(i-1,1)))>=0)
{v+=dx<<((l-i)<<2);}
else
{throw;}
}
return v;
}