C ++将十六进制字符串转换为有符号整数


135

我想在C ++中将十六进制字符串转换为32位带符号整数。

因此,例如,我有一个十六进制字符串“ fffefffe”。其二进制表示为11111111111111101111111111111110。其带符号整数表示为:-65538。

如何在C ++中进行此转换?这也需要适用于非负数。例如,十六进制字符串“ 0000000A”(二进制为00000000000000000000000000001010),十进制为10。


2
注意。对于sizeof(int)== 4的系统,您只会得到-65538
Martin York

3
@马丁·约克,他没有提到int。“32位带符号整数”可以是int32_t或__int32等
基里尔V. Lyadvinsky

Answers:


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/stolhttp://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,这是一个简单的词法转换类型,它不进行错误检查:

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
Clayton

@ jmanning2k,是的,如果我不将std :: hex放在字符串中,那么将boost和我的lexical_cast barf都放在十六进制字符串(即使带有0x前缀)上也很奇怪。
埃文·特兰

1
@SteveWilkinson:阅读以“ EDIT ” 开头的段落。它说明了您的使用方式std::hex
Evan Teran 2012年

1
对于,stringstream应检查ss.good() && ss.eof()以确保没有错误发生。
atoMerz 2014年

1
这种“stoul”保存我的逻辑
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+ overflow使用strtol时会有。与strtoul将没有溢出并返回值将被转换成long以产生正确的结果(-65538)。因此,您的回答几乎正确:)
Kirill V. Lyadvinsky

8
+1。因为strtol(或strtoul)比使用stringstream更快。
Kirill V. Lyadvinsky

27

安迪·布坎南(Andy Buchanan),就坚持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");

这样,您就不需要每个int类型一个impl。


1
我也应该采取这一步骤,但是我发现我想限制尖括号的扩散。对于这种情况,我认为违反“请勿重复代码”规则是合理的。:-)
Andy J Buchanan 2010年

不幸的是,这是必要的,但是做得很好。添加到我的个人STL / Boost扩展/修复标头中。谢谢!
蒂姆·西尔维斯特

不幸的是,这仅适用于无符号转换。因此,您不能将0xFFFFFFFF转换为-1。
fmuecke 2012年

@fmuecke:这是因为0xFFFFFFFF是有符号整数溢出,这是未定义的行为。
Billy ONeal 2012年

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这就是为什么在这种情况下没有溢出的原因。

好的,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在控制台中打印。


9

这是我在其他地方找到的简单有效的方法:

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

请注意,您可能更喜欢使用无符号长整数/长整数来接收值。另外请注意,c_str()函数只是将std :: string转换为const char *。

因此,如果您已准备好const char *,请直接直接使用该变量名,如下所示[我也显示了无符号long变量用于更大十六进制数的用法。不要将其与使用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);

这工作得很好(只要您根据需要使用适当的数据类型)。


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)。
加比·达瓦尔

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

试试这个。这种解决方案有点冒险。没有检查。该字符串只能具有十六进制值,并且字符串长度必须与返回类型的大小匹配。但是不需要额外的标题。

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整除

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.