C++ convertir cadena hexadecimal a entero con signo


Quiero convertir una cadena hexadecimal a un entero con signo de 32 bits en C++.

Así que, por ejemplo, tengo la cadena hexadecimal "fffefffe". La representación binaria de esto es 111111111111111101111111111111111110. La representación entera con signo de esto es: -65538.

¿Cómo hago esta conversión en C++? Esto también debe funcionar para números no negativos. Por ejemplo, la cadena hexadecimal "0000000A", que es 000000000000000000000000001010 en binario, y 10 en decimal.

Author: Clayton, 2009-07-01

8 answers

Use std::stringstream

unsigned int x;   
std::stringstream ss;
ss << std::hex << "fffefffe";
ss >> x;

El siguiente ejemplo produce -65538 como resultado:

#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;
}

EDITAR: Actualización de C++11. En el nuevo estándar, hay algunas nuevas funciones de utilidad que puede hacer uso de! específicamente, hay una familia de funciones "string to number" (http://en.cppreference.com/w/cpp/string/basic_string/stol y http://en.cppreference.com/w/cpp/string/basic_string/stoul ). Estos son esencialmente envoltorios delgados alrededor de la cadena de C a funciones de conversión de números, pero saber cómo tratar con un std::string

Entonces, la respuesta más simple para un código más nuevo probablemente se vería así: {[12]]}

std::string s = "0xfffefffe";
unsigned int x = std::stoul(s, nullptr, 16);

NOTA: A continuación está mi respuesta original, que como dice la edición no es una respuesta completa. Para una solución funcional. Pega el código encima de la línea: -).


EDITAR: Parece que desde lexical_cast<> se define para tener semántica de conversión de flujo. Lamentablemente, los streams no entienden la notación "0x". Así que ambos el boost::lexical_cast y mi mano rodada uno no se ocupan bien con las cuerdas hexagonales. La solución anterior que establece manualmente el flujo de entrada en hexadecimal lo manejará bien.

Boost tiene algunas cosas para hacer esto también, que tiene algunas buenas capacidades de comprobación de errores también. Puedes usarlo así:

try {
    unsigned int x = lexical_cast<int>("0x0badc0de");
} catch(bad_lexical_cast &) {
    // whatever you want to do...
}

Si no tiene ganas de usar boost, aquí hay una versión ligera de lexical cast que no verifica errores:

template<typename T2, typename T1>
inline T2 lexical_cast(const T1 &in) {
    T2 out;
    std::stringstream ss;
    ss << in;
    ss >> out;
    return out;
}

Que puedes usar así:{[12]]}

// though this needs the 0x prefix so it knows it is hex
unsigned int x = lexical_cast<unsigned int>("0xdeadbeef"); 
 184
Author: Evan Teran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-26 01:40:04

Para un método que funcione con C y C++, es posible que desee considerar el uso de la función de biblioteca estándar 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;
    }
}
 54
Author: Geof Sawaya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-12 00:52:11

Andy Buchanan, en cuanto a C++, me gustó el tuyo, pero tengo algunos mods:

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;
    }
};

Usado como

uint32_t value = boost::lexical_cast<HexTo<uint32_t> >("0x2a");

De esa manera no necesitas un impl por tipo int.

 26
Author: Mike Lundy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-17 02:08:04

El ejemplo de trabajo con strtoul será:

#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 convierte string a long. En mi computadora numeric_limits<long>::max() da 0x7fffffff. Obviamente que 0xfffefffe es mayor que 0x7fffffff. Así que strtol devuelve MAX_LONG en lugar del valor deseado. strtoul convierte string a unsigned long por eso no hay desbordamiento en este caso.

Ok, strtol está considerando la cadena de entrada no como un entero con signo de 32 bits antes de la conversión. Muestra divertida con 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;
    }
}

El código anterior imprime -65538 en la consola.

 14
Author: Kirill V. Lyadvinsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-02 06:20:27

Aquí hay un método simple y de trabajo que encontré en otro lugar:

string hexString = "7FF";
int hexNumber;
sscanf(hexString.c_str(), "%x", &hexNumber);

Tenga en cuenta que puede preferir usar unsigned long integer/long integer, para recibir el valor. Otra nota, la función c_str () simplemente convierte la cadena std::a const char* .

Así que si tiene un const char* listo, simplemente siga adelante con el uso de ese nombre de variable directamente, como se muestra a continuación [También estoy mostrando el uso de la variable larga sin signo para un número hexadecimal más grande. No lo confunda con el caso de teniendo const char* en lugar de 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);

Esto funciona perfectamente bien (siempre que utilice los tipos de datos adecuados según sus necesidades).

 8
Author: AamodG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-19 20:25:26

Tuve el mismo problema hoy, así es como lo resolví para poder mantener 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...

(Encontré esta página cuando estaba buscando una manera menos sucky: -)

Saludos, A.

 6
Author: Andy J Buchanan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-26 15:01:38

Esto funcionó para mí:

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 
 3
Author: mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-28 20:56:00

Otro método

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;
}
 -1
Author: stentor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-07 01:49:50