std::hex 无法处理负数?
std::hex cannot process negative numbers?
我正在尝试使用 std::hex 从文件中读取十六进制整数。
0
a
80000000
...
这些整数有正有负。
似乎std::hex不能处理负数。我不明白为什么,也没有在文档中看到定义的范围。
这是一个测试台:
#include <iostream>
#include <sstream>
#include <iomanip>
int main () {
int i;
std::stringstream ss;
// This is the smallest number
// That can be stored in 32 bits -1*2^(31)
ss << "80000000";
ss >> std::hex >> i;
std::cout << std::hex << i << std::endl;
}
输出:
7fffffff
设置 std::hex
告诉流读取整数标记 as though using std::scanf
with the %X
formatter. %X
reads into an unsigned integer,即使位模式适合,结果值也会溢出 int
。由于溢出,读取失败,无法相信 i
的内容包含预期值。旁注:i
如果编译为 C++11 或更新版本或在 c++11 之前未更改其当前未指定值,则将设置为 0。
请注意,如果我们在读取后检查流状态,这是您应该经常做的事情,我们可以看到读取失败:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdint> // added for fixed width integers.
int main () {
int32_t i; //ensure 32 bit int
std::stringstream ss;
// This is the smallest number
// That can be stored in 32 bits -1*2^(31)
ss << "80000000";
if (ss >> std::hex >> i)
{
std::cout << std::hex << i << std::endl;
}
else
{
std::cout << "FAIL! " << std::endl; //will execute this
}
}
解决方案是,正如提问者在评论中推测的那样,读入 unsigned int
(如果 int
不是 32 位,uint32_t
以避免进一步的意外)。以下是代码的零意外版本,使用 memcpy
将读取的确切位模式传输到 i
.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdint> // added for fixed width integers.
#include <cstring> //for memcpy
int main () {
int32_t i; //ensure 32 bit int
std::stringstream ss;
// This is the smallest number
// That can be stored in 32 bits -1*2^(31)
ss << "80000000";
uint32_t temp;
if (ss >> std::hex >> temp)
{
memcpy(&i, &temp, sizeof(i));// probably compiles down to cast
std::cout << std::hex << i << std::endl;
}
else
{
std::cout << "FAIL! " << std::endl;
}
}
话虽如此,暂时深入了解老派的 C 风格编码
if (ss >> std::hex >> *reinterpret_cast<uint32_t*>(&i))
{
std::cout << std::hex << i << std::endl;
}
else
{
std::cout << "FAIL! " << std::endl;
}
违反了 the strict aliasing rule,但是一旦 32 位 int
被 int32_t i;
强制使用,我会很惊讶地看到它失败了。这在最近的 C++ 标准中甚至可能是合法的,因为“类型相似”,但我仍在思考这个问题。
我正在尝试使用 std::hex 从文件中读取十六进制整数。
0
a
80000000
...
这些整数有正有负。
似乎std::hex不能处理负数。我不明白为什么,也没有在文档中看到定义的范围。
这是一个测试台:
#include <iostream>
#include <sstream>
#include <iomanip>
int main () {
int i;
std::stringstream ss;
// This is the smallest number
// That can be stored in 32 bits -1*2^(31)
ss << "80000000";
ss >> std::hex >> i;
std::cout << std::hex << i << std::endl;
}
输出:
7fffffff
设置 std::hex
告诉流读取整数标记 as though using std::scanf
with the %X
formatter. %X
reads into an unsigned integer,即使位模式适合,结果值也会溢出 int
。由于溢出,读取失败,无法相信 i
的内容包含预期值。旁注:i
如果编译为 C++11 或更新版本或在 c++11 之前未更改其当前未指定值,则将设置为 0。
请注意,如果我们在读取后检查流状态,这是您应该经常做的事情,我们可以看到读取失败:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdint> // added for fixed width integers.
int main () {
int32_t i; //ensure 32 bit int
std::stringstream ss;
// This is the smallest number
// That can be stored in 32 bits -1*2^(31)
ss << "80000000";
if (ss >> std::hex >> i)
{
std::cout << std::hex << i << std::endl;
}
else
{
std::cout << "FAIL! " << std::endl; //will execute this
}
}
解决方案是,正如提问者在评论中推测的那样,读入 unsigned int
(如果 int
不是 32 位,uint32_t
以避免进一步的意外)。以下是代码的零意外版本,使用 memcpy
将读取的确切位模式传输到 i
.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdint> // added for fixed width integers.
#include <cstring> //for memcpy
int main () {
int32_t i; //ensure 32 bit int
std::stringstream ss;
// This is the smallest number
// That can be stored in 32 bits -1*2^(31)
ss << "80000000";
uint32_t temp;
if (ss >> std::hex >> temp)
{
memcpy(&i, &temp, sizeof(i));// probably compiles down to cast
std::cout << std::hex << i << std::endl;
}
else
{
std::cout << "FAIL! " << std::endl;
}
}
话虽如此,暂时深入了解老派的 C 风格编码
if (ss >> std::hex >> *reinterpret_cast<uint32_t*>(&i))
{
std::cout << std::hex << i << std::endl;
}
else
{
std::cout << "FAIL! " << std::endl;
}
违反了 the strict aliasing rule,但是一旦 32 位 int
被 int32_t i;
强制使用,我会很惊讶地看到它失败了。这在最近的 C++ 标准中甚至可能是合法的,因为“类型相似”,但我仍在思考这个问题。