C ++は16進文字列を符号付き整数に変換します


135

16進文字列をC ++で32ビットの符号付き整数に変換したい。

したがって、たとえば、16進数の文字列 "fffefffe"があります。これのバイナリ表現は11111111111111101111111111111110です。これの符号付き整数表現は-65538です。

C ++でこの変換を行うにはどうすればよいですか?これは、負でない数に対しても機能する必要があります。たとえば、16進数の文字列「0000000A」は、2進数で00000000000000000000000000001010、10進数で10です。


2
注意。sizeof(int)== 4のシステムの場合のみ-65538を取得します
Martin York

3
@マーティンヨーク、彼は言及しなかったint。int32_tまたは__INT32等とすることができる「32ビット符号付き整数」
キリルV. Lyadvinsky

回答:


230

使用する 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、私の手で転がしたものも、16進数の文字列をうまく扱えません。入力ストリームを手動で16進数に設定する上記のソリューションは、それをうまく処理します。

Boostにはこれを行うためのいくつかの機能があり、これには優れたエラーチェック機能もあります。次のように使用できます。

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

ブーストを使用したくない場合は、エラーチェックを行わない字句キャストのライトバージョンを次に示します。

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

1
その方法を使用すると、152144602の整数値が返されます
クレイトン

@ jmanning2k、そうですね、文字列にstd :: hexを入れないと、16進文字列(0x接頭辞があっても)のブーストとlexical_cast barfの両方が奇妙です。
エヴァン・テラン

1
@SteveWilkinson:「EDIT」で始まる段落を読んでください。それはあなたがどのように使用する必要があるかを説明しますstd::hex
エヴァン・テラン2012年

1
以下のためstringstreamの一つはチェックする必要がありますss.good() && ss.eof()必ずエラーが発生しなかっ作ります。
atoMerz 2014年

1
この「魂」は私の論理を救う
vincenzopalazzo

60

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

2
strtoulnot を使用する必要がありstrtolます。+ overflowstrtolを使用する場合があります。strtoulオーバーフローと戻り値は存在しないに変換されlong、正しい結果(-65538)を生成します。だから、あなたの答えはほとんど右:)
キリルV. Lyadvinsky

8
+1。文字列ストリームを使用するよりもstrtol(またはstrtoul)が高速だからです。
キリルV.リヤドビンスキー2009

27

Andy Buchananは、C ++にこだわる限り、私はあなたのものを好きでしたが、いくつかのmodを持っています:

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

そうすれば、int型ごとに1つの実装は必要ありません。


1
私もその一歩を踏み出しただろうが、山括弧の急増を制限したいと思う。この場合、「コードを複製しない」というルールを破ることは正当化されると感じました。:-)
アンディJブキャナン

残念ながらそれは必要ですが、うまく行われています。個人のSTL / Boost extensions / fixesヘッダーに追加されました。ありがとう!
Tim Sylvester

残念ながら、これは符号なしの変換でのみ機能します。したがって、0xFFFFFFFFを-1に変換することはできません。
fmuecke

@fmuecke:これは、0xFFFFFFFFが符号なし整数オーバーフローであり、これは未定義の動作であるためです。
Billy ONeal

15

を使用した作業例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に変換さstringlongます。私のコンピュータでnumeric_limits<long>::max()与える0x7fffffff。明らかにそれ0xfffefffeはより大きいです0x7fffffff。したがって、必要な値の代わりにstrtol戻りMAX_LONGます。strtoul変換stringunsigned longそれは、この場合に、なぜオーバーフローません。

OK、strtolconvertation前ではない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はコンソールに出力されます。


9

ここに私が他の場所で見つけたシンプルで実用的な方法があります:

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

値を受け取るには、符号なし長整数/長整数を使用することをお勧めします。また、c_str()関数はstd :: stringをconst char *に変換するだけです。

したがって、const char *の準備ができている場合は、以下に示すように、その変数名を直接使用して先に進んでください。文字列の代わりにconst char *を使用する場合と混同しないでください]:

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

これはまったく問題なく動作します(必要に応じて適切なデータ型を使用する場合)。


6

今日も同じ問題が発生しました。これを解決して、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...

(私はそれほど厄介な方法を探していたときにこのページを見つけました:-)

乾杯、A。


1
コードに些細なコンパイルエラーがあります-outvalueが定義されていません(outValueである必要があります)。
Gabi Davar

3

これは私のために働きました:

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

これを試して。このソリューションは少し危険です。チェックはありません。文字列は16進値のみを持ち、文字列の長さは戻り値の型のサイズと一致する必要があります。しかし、追加のヘッダーは必要ありません。

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で割り切れる必要があります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.