C ++ преобразует шестнадцатеричную строку в целое число со знаком

StackOverflow https://stackoverflow.com/questions/1070497

  •  21-08-2019
  •  | 
  •  

Вопрос

Я хочу преобразовать шестнадцатеричную строку в 32-битное целое число со знаком в C ++.

Так, например, у меня есть шестнадцатеричная строка "fffefffe".Двоичным представлением этого является 111111111111111110111111111111111110.Знаковое целочисленное представление этого является:-65538.

Как мне выполнить это преобразование на C ++?Это также должно работать для неотрицательных чисел.Например, шестнадцатеричная строка "0000000A", которая равна 000000000000000000000000000000001010 в двоичной системе счисления и 10 в десятичной.

Это было полезно?

Решение

использование 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).По сути, это тонкие оболочки вокруг функций преобразования строк C в числовые, но вы знаете, как обращаться с 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, вот облегченная версия lexical cast, которая не выполняет проверку ошибок:

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, так и с ++, вы можете рассмотреть возможность использования стандартной библиотечной функции 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);

Пожалуйста, обратите внимание, что для получения значения вы можете предпочесть использовать длинное целое число без знака / long integer .Еще одно замечание, функция c_str() просто преобразует std::string в const char* .

Поэтому, если у вас готов const char *, просто продолжайте использовать это имя переменной напрямую, как показано ниже [Я также показываю использование длинной переменной без знака для большего шестнадцатеричного числа.Не путайте это со случаем использования 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...

(Нашел эту страницу, когда искал менее отстойный способ :-)

Ваше здоровье, А.

У меня это сработало:

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 

другой метод

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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top