我想在C++中将十六进制字符串转换为32位有符号整数。
例如,我有一个十六进制字符串"fffefffe"。其二进制表示为11111111111111101111111111111110。其有符号整数表示为:-65538。
如何在C++中进行此转换?这也需要适用于非负数。例如,十六进制字符串"0000000A",其二进制表示为00000000000000000000000000001010,十进制表示为10。
使用 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;
}
std::string
。std::string s = "0xfffefffe";
unsigned int x = std::stoul(s, nullptr, 16);
注意:下面是我的原始答案,正如编辑所说的那样,这不是一个完整的答案。对于一个功能性的解决方案,请将代码放在上面的行之上 :-).
看起来由于lexical_cast<>
被定义为具有流转换语义,因此它不支持"0x"表示法。很遗憾,流无法理解"0x"表示法。因此,boost::lexical_cast
和我手动编写的代码都无法处理十六进制字符串。上面的解决方案手动将输入流设置为十六进制,可以很好地处理它。
Boost有一些工具也可以做到这一点,并具有一些良好的错误检查功能。您可以像这样使用它:
try {
unsigned int x = lexical_cast<int>("0x0badc0de");
} catch(bad_lexical_cast &) {
// whatever you want to do...
}
如果您不想使用boost,这里有一个轻量级的lexical cast版本,它不进行错误检查:
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");
std::hex
。 - Evan Teranstringstream
,应该检查 ss.good() && ss.eof()
来确保没有发生错误。 - atoMerz0xfffefffe
对应于有符号整数值,为什么您的变量 x
是一个 unsigned int
?同样,为什么您必须使用 stoul
而不是 stoi
来使其工作?我尝试了 stoi
,但它抛出了一个异常。感谢您提供的任何帮助! - user3266738如果你想要一个适用于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
而不是 strtol
。在使用 strtol
时会出现 + 溢出
的情况。使用 strtoul
将不会出现溢出情况,并且返回的值将被转换为 long
类型以产生正确的结果(-65538)。所以你的答案几乎是正确的 :) - Kirill V. LyadvinskyAndy 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");
那样的话,你就不需要为每种整数类型都编写一个实现。使用 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
转换为无符号长整型,因此不会出现溢出。
好的,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
。
以下是我在其他地方找到的一个简单可行的方法:
string hexString = "7FF";
int hexNumber;
sscanf(hexString.c_str(), "%x", &hexNumber);
请注意,您可能更喜欢使用无符号长整型/长整型来接收该值。另一个注意点是,c_str()函数只是将std::string转换为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);
只要您根据自己的需求使用适当的数据类型,这将完美地运作。
今天我遇到了同样的问题,以下是我如何解决它以保留 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。
只需使用stoi/stol/stoll,例如:
std::cout << std::stol("fffefffe", nullptr, 16) << std::endl;
输出结果:4294901758
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
试一下这个。这个解决方案有一些风险。没有检查。字符串必须只包含十六进制值,且字符串长度必须与返回类型大小匹配。但不需要额外的头文件。
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";
}
std::hex
和std::stoul()
以及sscanf()
都是宽容的,所以如果我传入一个错误的"FK",它会将其解释为15(忽略K并将F视为十六进制数)。在hextob函数中,我将返回值改为std::cerr<<"ERROR: invalid ch='"<<ch<<"'"<<"\n";exit(1);
,这样我可以确保输入是完美的。但是我现在使用了另一种方式,对于最多0xFF的情况,int hexaTo(const char* pch) {return hextob(pch[0])*16+hextob(pch[1]);}
。 - Aquarius Power如果您想要将无符号数字转换为不同的进制,那么在C/C++中自己实现是相当简单的,只需使用最少的依赖(语言本身没有提供的唯一运算符是pow()
函数)。
在数学术语中,一个正序数d在进制b下,有n个数字位,可以使用以下公式转换为十进制:
例子:将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));
}
int
。"32位有符号整数"可能是int32_t
或__int32
等。 - Kirill V. Lyadvinsky