web-dev-qa-db-fra.com

C ++ convertir une chaîne hexadécimale en entier signé

Je veux convertir une chaîne hexadécimale en un entier signé 32 bits en C++.

Ainsi, par exemple, j'ai la chaîne hexagonale "fffefffe". La représentation binaire de ceci est 1111111111111111111111111111111110. La représentation entière signée de ceci est: -65538.

Comment puis-je faire cette conversion en C++? Cela doit également fonctionner pour les nombres non négatifs. Par exemple, la chaîne hex "0000000A", qui est 00000000000000000000000000001010 en binaire et 10 en décimal.

123
Clayton

utiliser std::stringstream

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

l'exemple suivant produit -65538 comme résultat:

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

Dans la nouvelle norme C++ 11, vous pouvez utiliser quelques nouvelles fonctions utilitaires! en particulier, il existe une famille de fonctions "chaîne vers nombre" ( http://en.cppreference.com/w/cpp/string/basic_string/stol et http: // en .cppreference.com/w/cpp/string/chaîne_base/stoul ). Ce sont essentiellement des wrappers minces autour des fonctions de conversion chaîne en nombre de C, mais ils savent comment traiter un std::string

Ainsi, la réponse la plus simple pour un code plus récent ressemblerait probablement à ceci:

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

REMARQUE: Voici ma réponse originale, qui, comme le dit la modification, n'est pas une réponse complète. Pour une solution fonctionnelle, collez le code au-dessus de la ligne :-).

Il semble que, puisque lexical_cast<> soit défini comme ayant une sémantique de conversion de flux. Malheureusement, les flux ne comprennent pas la notation "0x". Donc, le boost::lexical_cast et ma main roulée ne traitent pas bien les chaînes hexagonales. La solution ci-dessus qui définit manuellement le flux d'entrée sur hexadécimal le traitera parfaitement.

Boost a quelques trucs à faire aussi, ce qui a aussi quelques capacités de vérification des erreurs de Nice. Vous pouvez l'utiliser comme ceci:

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

Si vous ne souhaitez pas utiliser de boost, voici une version allégée de la distribution lexicale qui ne vérifie pas les erreurs:

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

que vous pouvez utiliser comme ceci:

// though this needs the 0x prefix so it knows it is hex
unsigned int x = lexical_cast<unsigned int>("0xdeadbeef"); 
210
Evan Teran

Pour une méthode fonctionnant à la fois en C et en C++, vous pouvez envisager d'utiliser la fonction de bibliothèque standard 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;
    }
}
56
anon

Andy Buchanan, pour ce qui est du collage au C++, j'ai aimé le vôtre, mais j'ai quelques 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;
    }
};

Utilisé comme

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

De cette façon, vous n'avez pas besoin d'un impl par type int.

26
Mike Lundy

Exemple de travail avec strtoul sera:

#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 convertit string en long. Sur mon ordinateur, numeric_limits<long>::max() donne 0x7fffffff. Il est évident que 0xfffefffe est supérieur à 0x7fffffff. Ainsi, strtol renvoie MAX_LONG au lieu de la valeur souhaitée. strtoul convertit string en unsigned long c'est pourquoi il n'y a pas de dépassement de capacité dans ce cas.

Ok, strtol considère la chaîne d'entrée comme un entier signé 32 bits avant la conversion. Échantillon drôle avec 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;
    }
}

Le code ci-dessus imprime -65538 dans la console.

15

Voici une méthode simple et efficace que j'ai trouvée ailleurs:

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

Veuillez noter que vous préférerez peut-être utiliser un entier long non signé/un entier long pour recevoir la valeur. Une autre note, la fonction c_str () convertit simplement std :: string en const char *.

Donc, si vous avez un const char * ready, continuez simplement en utilisant ce nom de variable directement, comme indiqué ci-dessous Ne le confondez pas avec le cas de const char * au lieu 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);

Cela fonctionne parfaitement (à condition que vous utilisiez les types de données appropriés à vos besoins).

8
AamodG

J'ai eu le même problème aujourd'hui, voici comment je l'ai résolu pour que je puisse garder 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...

(J'ai trouvé cette page alors que je cherchais un moyen moins pénible :-)

À la vôtre, A.

6
Andy J Buchanan

Cela a fonctionné pour moi:

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
mike