简体   繁体   English

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

[英]C++ convert hex string to signed integer

I want to convert a hex string to a 32 bit signed integer in C++.我想在 C++ 中将十六进制字符串转换为 32 位有符号整数。

So, for example, I have the hex string "fffefffe".因此,例如,我有十六进制字符串“ffeffeff”。 The binary representation of this is 11111111111111101111111111111110. The signed integer representation of this is: -65538.它的二进制表示是 11111111111111101111111111111110。它的有符号整数表示是:-65538。

How do I do this conversion in C++?我如何在 C++ 中进行这种转换? This also needs to work for non-negative numbers.这也需要适用于非负数。 For example, the hex string "0000000A", which is 00000000000000000000000000001010 in binary, and 10 in decimal.例如,十六进制字符串“0000000A”,二进制为00000000000000000000000000001010,十进制为10。

use std::stringstream使用std::stringstream

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

the following example produces -65538 as its result:以下示例生成-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;
}

In the new C++11 standard, there are a few new utility functions which you can make use of!在新的 C++11 标准中,您可以使用一些新的实用函数! specifically, there is a family of "string to number" functions ( http://en.cppreference.com/w/cpp/string/basic_string/stol and http://en.cppreference.com/w/cpp/string/basic_string/stoul ).具体来说,有一系列“字符串到数字”函数( http://en.cppreference.com/w/cpp/string/basic_string/stolhttp://en.cppreference.com/w/cpp/string/ basic_string/stoul )。 These are essentially thin wrappers around C's string to number conversion functions, but know how to deal with a std::string这些本质上是围绕 C 的字符串到数字转换函数的薄包装,但知道如何处理std::string

So, the simplest answer for newer code would probably look like this:因此,较新代码的最简单答案可能如下所示:

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

NOTE: Below is my original answer, which as the edit says is not a complete answer.注意:以下是我的原始答案,正如编辑所说,这不是一个完整的答案。 For a functional solution, stick the code above the line :-).对于功能性解决方案,将代码粘贴在行上方:-)。

It appears that since lexical_cast<> is defined to have stream conversion semantics.似乎因为lexical_cast<>被定义为具有流转换语义。 Sadly, streams don't understand the "0x" notation.可悲的是,流不理解“0x”符号。 So both the boost::lexical_cast and my hand rolled one don't deal well with hex strings.所以boost::lexical_cast和我的手卷都不能很好地处理十六进制字符串。 The above solution which manually sets the input stream to hex will handle it just fine.上述手动将输入流设置为十六进制的解决方案可以很好地处理它。

Boost has some stuff to do this as well, which has some nice error checking capabilities as well. Boost 也有一些东西可以做到这一点,它也有一些很好的错误检查功能。 You can use it like this:你可以这样使用它:

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

If you don't feel like using boost, here's a light version of lexical cast which does no error checking:如果您不想使用 boost,这里有一个不进行错误检查的词法转换的精简版:

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

which you can use like this:你可以这样使用:

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

For a method that works with both C and C++, you might want to consider using the standard library function strtol().对于同时适用于 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;
    }
}

Andy Buchanan, as far as sticking to C++ goes, I liked yours, but I have a few mods: 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;
    }
};

Used like像用过

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

That way you don't need one impl per int type.这样你就不需要每个 int 类型一个 impl 。

Working example with strtoul will be: 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 converts string to long . strtolstring转换为long On my computer numeric_limits<long>::max() gives 0x7fffffff .在我的电脑上numeric_limits<long>::max()给出0x7fffffff Obviously that 0xfffefffe is greater than 0x7fffffff .显然0xfffefffe大于0x7fffffff So strtol returns MAX_LONG instead of wanted value.所以strtol返回MAX_LONG而不是想要的值。 strtoul converts string to unsigned long that's why no overflow in this case. strtoulstring转换为unsigned long这就是为什么在这种情况下没有溢出的原因。

Ok, strtol is considering input string not as 32-bit signed integer before convertation.好的, strtol在转换前考虑输入字符串不是 32 位有符号整数。 Funny sample with strtol :带有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;
    }
}

The code above prints -65538 in console.上面的代码在控制台中打印-65538

Here's a simple and working method I found elsewhere:这是我在别处找到的一种简单而有效的方法:

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

Please note that you might prefer using unsigned long integer/long integer, to receive the value.请注意,您可能更喜欢使用无符号长整数/长整数来接收值。 Another note, the c_str() function just converts the std::string to const char* .另一个注意事项, c_str() 函数只是将 std::string 转换为 const char* 。

So if you have a const char* ready, just go ahead with using that variable name directly, as shown below [I am also showing the usage of the unsigned long variable for a larger hex number.因此,如果您准备好 const char*,请直接使用该变量名称,如下所示 [我还展示了 unsigned long 变量用于更大的十六进制数的用法。 Do not confuse it with the case of having const char* instead of string]:不要将它与使用 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);

This works just perfectly fine (provided you use appropriate data types per your need).这工作得很好(前提是您根据需要使用适当的数据类型)。

I had the same problem today, here's how I solved it so I could keep lexical_cast<>我今天遇到了同样的问题,这是我解决它的方法,所以我可以保留 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...

(Found this page when I was looking for a less sucky way :-) (当我正在寻找一种不那么糟糕的方式时找到了这个页面:-)

Cheers, A.干杯,A.

This worked for me:这对我有用:

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 

Try this.尝试这个。 This solution is a bit risky.这个解决方案有点冒险。 There are no checks.没有检查。 The string must only have hex values and the string length must match the return type size.字符串必须只有十六进制值,并且字符串长度必须与返回类型大小匹配。 But no need for extra headers.但不需要额外的标题。

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

Usage:用法:

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

Note: the length of the string must be divisible by 2注意:字符串的长度必须能被 2 整除

just use stoi/stol/stoll for example:只需使用 stoi/stol/stoll 例如:

std::cout << std::stol("fffefffe", nullptr, 16) << std::endl;

output: 4294901758输出:4294901758

For those looking to convert number base for unsigned numbers, it is pretty trivial to do yourself in both C/C++ with minimal dependency (only operator not provided by the language itself is pow() function).对于那些希望将数基转换为无符号数的人来说,在 C/C++ 中以最小的依赖性(只有语言本身不提供的运算符是pow()函数)自己做是非常简单的。

In mathematical terms, a positive ordinal number d in base b with n number of digits can be converted to base 10 using:在数学术语中,一个以b为基数的具有n个数字的正序数d可以使用以下方法转换为以 10 为基数:

数学求和

Example: Converting base 16 number 00f looks like:示例:转换基数为 16 的数字00f如下所示:

数学求和 = 0*16^2 + 0*16^1 + 16*16^0 = 15 = 0*16^2 + 0*16^1 + 16*16^0 = 15

C/C++ Example: C/C++ 示例:

#include <math.h>

unsigned int to_base10(char *d_str, int len, int base)
{
    if (len < 1) {
        return 0;
    }
    char d = d_str[0];
    // chars 0-9 = 48-57, chars a-f = 97-102
    int val = (d > 57) ? d - ('a' - 10) : d - '0';
    int result = val * pow(base, (len - 1));
    d_str++; // increment pointer
    return result + to_base10(d_str, len - 1, base);
}

int main(int argc, char const *argv[])
{
    char n[] = "00f"; // base 16 number of len = 3
    printf("%d\n", to_base10(n, 3, 16));
}

another method 另一种方法

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM