C ++ hex dizesini işaretli tamsayıya dönüştürür


135

C ++ bir 32 bit imzalı tamsayı bir hex dizesini dönüştürmek istiyorum.

Yani, örneğin, onaltılık dize "fffefffe" var. Bunun ikili gösterimi 11111111111111101111111111111110'dur. Bunun imzalı tamsayı gösterimi: -65538'dir.

Bu dönüşümü C ++ ile nasıl yapabilirim? Bunun negatif olmayan sayılar için de çalışması gerekir. Örneğin, onaltılı olarak 00000000000000000000000000001010 ikili ve 10 olan onaltılık dize "0000000A".


2
Not. Sizeof (int) == 4
Martin York

3
@Martin York, bahsetmedi int. "32 bit işaretli tam sayı" int32_t veya __int32 vb
. Olabilir

Yanıtlar:


230

kullanım std::stringstream

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

aşağıdaki örnek -65538bunun sonucunda ortaya çıkar:

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

Yeni C ++ 11 standardında, yararlanabileceğiniz birkaç yeni yardımcı program işlevi vardır! özellikle, "string to number" işlevlerinden oluşan bir aile vardır ( http://en.cppreference.com/w/cpp/string/basic_string/stol ve http://en.cppreference.com/w/cpp/string/ basic_string / stoul ). Bunlar esasen C'nin sayı dönüştürme fonksiyonuna dizesi etrafındaki ince sargılardır, ancak birstd::string

Yani, yeni kod için en basit cevap muhtemelen şöyle görünecektir:

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

NOT: Aşağıda, düzenlemenin söylediği gibi tam bir cevap olmayan orijinal cevabım yer almaktadır. İşlevsel bir çözüm için, kodu satırın üstüne yapıştırın :-).

O zamandan beri lexical_cast<>, akış dönüşüm semantiği olduğu tanımlanmıştır. Maalesef akışlar "0x" gösterimini anlamıyor. Yani hem boost::lexical_castbenim hem de elimden biri altıgen dizelerle iyi başa çıkmıyor. Giriş akışını el ile onaltılık değere ayarlayan yukarıdaki çözüm, iyi işleyecektir.

Boost da bunu yapmak için bazı şeyler var , bu da bazı güzel hata kontrol yetenekleri vardır. Bu şekilde kullanabilirsiniz:

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

Güçlendirme kullanmak istemiyorsanız, hata kontrolü yapmayan, lexical cast'ın hafif bir sürümü:

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

Bu şekilde kullanabilirsiniz:

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

1
Bu yöntemi kullandığımda 152144602
Clayton

@ jmanning2k, evet, dize std :: hex koymazsanız, hem hex hem de hex dizelerimde (0x öneki ile bile) lexical_cast barf'm garip.
Evan Teran

1
@SteveWilkinson: " EDIT " ile başlayan paragrafı okuyun . Nasıl kullanmanız gerektiğini açıklarstd::hex
Evan Teran

1
İçin stringstreams biri kontrol etmelisiniz ss.good() && ss.eof()emin hata oluştu yapmak.
atoMerz

1
Bu "stoul" benim mantığı kurtarmak
vincenzopalazzo

60

Hem C hem de C ++ ile çalışan bir yöntem için, standart kütüphane işlevini strtol () kullanmayı düşünebilirsiniz.

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

2
Sen kullanmalıdır strtouldeğil strtol. + overflowStrtol kullanırken olacaktır . İle strtoulolacak hiçbir taşma ve geri değeri dönüştürülür longdoğru sonucu (-65.538) elde edilir. Cevabınız neredeyse doğru :)
Kirill V. Lyadvinsky

8
+1. Çünkü strtol (veya strtoul) stringstream kullanmaktan daha hızlıdır.
Kirill V. Lyadvinsky

27

Andy Buchanan, C ++ 'a bağlı kaldığınızda, sizinkini beğendim, ancak birkaç modum var:

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

Gibi kullanılır

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

Bu şekilde int türü başına bir implanta ihtiyacınız yoktur.


1
Ben de bu adımı atmış olurdum, ama açılı ayraçların çoğalmasını sınırlamak istediğimi fark ettim. Bu durumda "yinelenen kod yok" kuralının kırılmasının haklı olduğunu hissettim. :-)
Andy J Buchanan

Talihsiz, ama güzel yapılır. Kişisel STL / Boost uzantıları / düzeltmeleri başlığına eklendi. Teşekkürler!
Tim Sylvester

Ne yazık ki bu yalnızca imzasız dönüşüm için geçerlidir. Yani 0xFFFFFFFF dönüştürmek -1.
fmuecke

@fmuecke: 0xFFFFFFFF, tanımlanmamış bir davranış olan imzalı bir tamsayı taşmasıdır.
Billy ONeal

15

İle çalışma örneği 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;
    }
}

strtoldönüştürür stringiçin long. Bilgisayarımda numeric_limits<long>::max()verir 0x7fffffff. Açıkçası bu 0xfffefffedaha büyük 0x7fffffff. Yani istenen değer yerine strtoldöner MAX_LONG. strtouldönüştürür stringiçin unsigned longbu durumda neden hiçbir taşma var.

Tamam, strtolgiriş dizesini dönüştürme işleminden önce 32 bit işaretli tam sayı olarak görmüyor. Komik örnek 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;
    }
}

Yukarıdaki kod -65538konsolda yazdırılır .


9

İşte başka bir yerde bulduğum basit ve çalışan bir yöntem:

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

Değeri almak için işaretsiz uzun tamsayı / uzun tamsayı kullanmayı tercih edebileceğinizi lütfen unutmayın. Başka bir not, c_str () işlevi sadece std :: string'i const char * 'a dönüştürür.

Bir const char * hazırsanız, aşağıda gösterildiği gibi doğrudan bu değişken adını kullanmaya devam edin [Ayrıca daha büyük bir onaltılık sayı için işaretsiz uzun değişkenin kullanımını da göstereceğim. Dize yerine const char * olması durumunda karıştırmayın]:

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

Bu çok iyi çalışır (ihtiyacınıza uygun veri türlerini kullanmanız koşuluyla).


6

Bugün aynı sorunu yaşadım, işte böyle çözdüm, böylece lexical_cast'i tutabilirim <>

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...

(Bu sayfayı daha az emici bir yol ararken buldum :-)

Şerefe, A.


1
Kodun önemsiz derleme hatası var - outvalue tanımlanmadı (outValue olmalıdır).
Gabi Davar

3

Bu benim için çalıştı:

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 

0

Bunu dene. Bu çözüm biraz risklidir. Kontrol yok. Dize yalnızca onaltılık değerlere sahip olmalı ve dize uzunluğu döndürme türü boyutuyla eşleşmelidir. Ancak ek başlıklara gerek yok.

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

Kullanımı:

int main()
{
    char str[4] = {'f','f','f','f'};
    std::cout << hextot<int16_t>(str)  << "\n";
}

Not: Dizenin uzunluğu 2 ile bölünebilir olmalıdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.