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

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

例如,我有一个十六进制字符串“ fffefffe”。它的二进制表示是11111111111111111011111111110。它的有符号整数表示形式是: -65538。

如何在 C + + 中进行这种转换?这也需要对非负数起作用。例如,十六进制字符串“00000000A”,即二进制的00000000000000000000001010和十进制的10。

428778 次浏览

使用 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...
}

如果你不想使用 ost,这里有一个轻版本的词法强制转换,它不会检查错误:

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

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

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

strtolstring转换为 long。在我的电脑 numeric_limits<long>::max()0x7fffffff。显然,0xfffefffe大于 0x7fffffff。因此,strtol返回 MAX_LONG而不是所需的值。strtoulstring转换为 string1,这就是为什么在这种情况下没有溢出。

好的,在转换之前,strtol考虑的输入字符串不是32位有符号整数:

#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

今天我遇到了同样的问题,下面是我如何解决它的,这样我就可以保持 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.

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。

这对我很有效:

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

下面是我在其他地方找到的一个简单的工作方法:

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

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

因此,如果您已经准备好了 const char * ,那么直接使用该变量名即可,如下所示[我还展示了对较大的十六进制数使用无符号长变量的情况。不要将它与使用 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);

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

试试这个。这个解决方案有点冒险。没有支票。字符串必须只有十六进制值,并且字符串长度必须匹配返回类型的大小。但是不需要额外的头。

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

只要使用 Stoi/stol/stoll 例如:

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

产出: 4294901758

对于那些希望将数字基转换为无符号数字的人来说,在 C/C + + 中使用最小的依赖性(只有语言本身没有提供的操作符是 pow()函数)来完成自己的工作是相当琐碎的。

在数学术语中,以 B为基数的正序数 D和以 N为基数的数字可用以下方法转换为以10为基数的正序数:

math summation

例如: 转换16进制数 00f看起来像:

math summation= 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));
}