C++ 流负数转换
c++ stream negative number conversion
我在尝试读取一个充满十六进制形式的有符号整数并将其解析为向量的文本文件时遇到了C++问题。我使用了C++流到变量重定向(流>> var),似乎没有正确解析负数 - 变量获取值 0,并设置流失败标志。
如果我尝试使用 strtol() 函数转换字符串,结果符合预期。同样,如果我尝试首先将流重定向到无符号整数,然后将变量转换为有符号整数,则结果再次正确,并且不会报告流错误。
我在 Debian 9.1 (x64) 上使用 gcc 6.3.0,运行在至强 E5-2643 v3 系统上。
还有其他人遇到过这个问题吗?我希望转换的工作方式与 strtol 函数相同,并且不报告任何流错误。我是否缺少一些流设置/忘记在此处调用某些函数或设置某些标志?
任何建议将不胜感激。
下面附C++演示此问题的程序示例。
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
int main()
{
const char* minus_one = "0xffffffff";
std::stringstream ss;
ss << minus_one;
std::cout << "input string : " << ss.str() << "n"; // outputs "0xffffffff"
// C-style conversion
int32_t cint;
cint = strtol(ss.str().c_str(), NULL, 0);
std::cout << "strtol conv : " << cint << " (" << std::hex << cint << ")n"; // outputs "-1 (ffffffff)"
std::cout << std::dec;
// C++-style conversion
int32_t cppint;
ss >> std::hex >> cppint;
std::cout << std::dec << "ssextr conv : " << cppint << " (" << std::hex << cppint << ")n"; // outputs "0 (0)" <- ERROR
std::cout << std::dec;
if (ss.fail()) std::cout << "Error converting number.n";
// C++-style conversion with cast
uint32_t cppuint;
int32_t cppint2;
ss.clear();
ss.str(minus_one);
ss >> std::hex >> cppuint;
cppint2 = (int32_t)cppuint;
std::cout << std::dec << "ssextr cast conv: " << cppint2 << " (" << std::hex << cppint2 << ")n"; // outputs "-1 (0xffffffff)"
std::cout << std::dec;
if (ss.fail()) std::cout << "Error converting number.n";
exit(EXIT_SUCCESS);
}
int32_t cint;
cint = strtol(ss.str().c_str(), NULL, 0);
这会将值0xffffffff
读入long
,然后将其转换为int32_t
。如果long
大于 32 位,则strtol
工作并返回0xffffffff
即 4294967295,并将其转换为int32_t
会产生 -1。但这与从字符串中读取负数不同(如果long
是 32 位,那么它不会按预期工作,而是返回LONG_MAX
并将其转换为int32_t
,这是0x7fffffff
)。
int32_t cppint;
ss >> std::hex >> cppint;
这会尝试将值0xffffffff
读入int32_t
但0xffffffff
的值不适合该类型,因此读取值失败(就像当long
为 32 位时strtol
失败一样)。
与您的strtol
版本更接近的等效版本是:
int32_t cppint;
long l;
if (ss >> std::hex >> l)
cppint = l;
else
// handle error ...
期望能够将值0xffffffff
读取到有符号的 32 位整数中是不合理的。strtol
和 istream 不读取位模式,它们读取数字,并且数字0xffffffff
不适合有符号的 32 位整数。
如果第一个十六进制位是f
,那么C++使它成为一个"大数":"0x7fffffff"。似乎 c++ 不想将其表示为负数。 喜欢这个:
const char* minus_one = "0xf0000000"; //ssextr conv : 2147483647 (7fffffff)
std::stringstream ss;
ss << minus_one;
// C++ style conversion
int32_t cppint;
ss >> std::hex >> cppint;
std::cout << std::dec << "ssextr conv : " << cppint << " (" << std::hex << cppint << ")n";
std::cout << std::dec;
if (ss.fail()) {
std::cout << "Error converting number.n";
}
问题是十六进制表示法记录了无符号整数。strtol
是一个 C 函数,显然对负整数的十六进制表示形式更宽容,并在内部将字符串读取为无符号值,然后将其重新解释为有符号值。但即使在 C 中,对于strtol
和无法用有符号类型表示的无符号值的转换,也没有指定这样的处理结果是实现定义的信号或实现定义的信号被引发。(摘自草案 1570 C11 6.3.1.3 [转换] 有符号和无符号整数)
它很可能以这种方式工作,以免破坏大量遗留代码,但C++是一种较新的语言,实现者已决定对十六进制表示更加严格。
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 是否可以从int转换为enum类类型
- 了解 GLM- openGL 中的相机转换
- 将无符号char*转换为std::istream*C++