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

问题描述 投票:0回答:10

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

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

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

c++ integer hex signed
10个回答
275
投票

使用

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

72
投票

对于同时适用于 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;
    }
}

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 类型一个 impl。


16
投票

使用

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
string
转换为
long
。在我的电脑上
numeric_limits<long>::max()
给出
0x7fffffff
。显然
0xfffefffe
大于
0x7fffffff
。因此
strtol
返回
MAX_LONG
而不是想要的值。
strtoul
string
转换为
unsigned 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


10
投票

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

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

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

因此,如果您准备好了 const char*,只需直接使用该变量名称即可,如下所示 [我还展示了如何使用 unsigned 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);

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


7
投票

我今天遇到了同样的问题,这是我解决的方法,这样我就可以保留 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.


5
投票

只需使用 stoi/stol/stoll 例如:

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

输出:4294901758


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 

3
投票

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

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


1
投票

对于那些希望将基数转换为无符号数字的人来说,在 C/C++ 中以最小的依赖性进行操作是非常简单的(只有语言本身未提供的运算符是

pow()
函数)。

用数学术语来说,以 b 为基数且位数为 n 的正序数 d 可以使用以下方法转换为基数 10:

示例:转换 16 进制数字

00f
看起来像:

= 0*16^2 + 0*16^1 + 16*16^0 = 15

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));
}
© www.soinside.com 2019 - 2024. All rights reserved.